我正在尝试使用 JSF 2 构建一个自定义复合组件。我在这个组件中有一个对话框,我想在提交表单时显示该对话框,但是当我使用 appendToBody="false" 并且不工作时,该对话框永远不会显示我使用 appendToBody="true"。
我的搜索组件看起来像这样。
当用户在 inputText 中填写一些值并按下 seach 按钮时,应该会弹出如下对话框:
现在,我可以完成这项工作的唯一方法是在我的组件中使用两个按钮而不是一个。一个用于提交值,一个用于显示对话框。这是当我使用带有 appendToBody="false" 属性的对话框时。所以我的测试组件看起来像这样:
当我使用带有 appendToBody="true" 的对话框时,我可以一次提交并显示对话框,但是对话框还有其他问题,比如我无法关闭对话框。数据未更新等
这是我的代码(lov.xhtml):
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface componentType="lov">
<composite:attribute name="value" required="true" />
<composite:attribute name="definitionFile" required="true" />
<composite:attribute name="definitionName" required="true" />
</composite:interface>
<composite:implementation>
<h:outputStylesheet library="css" name="styles.css" />
<p:inputText id="lovInputText" styleClass="lovInputText"
value="#{cc.selectedValue}" binding="#{cc.lovInputText}" />
<p:commandButton styleClass="lovButton" icon="ui-icon-search"
onclick="searchAndSelect.show();" actionListener="#{cc.updateDialog}"
update="@form" />
<p:commandButton value="Open" icon="ui-icon-search"
onclick="searchAndSelect.show();" />
<h:outputLabel id="outputLabel" value="#{cc.selectedValue}" />
<p:dialog id="searchAndSelectDialog" header="Search and Select"
appendToBody="false" closable="false" resizable="false"
widgetVar="searchAndSelect" showEffect="fade" hideEffect="fade"
binding="#{cc.searchAndSelectDialog}">
<p:panelGrid>
<p:row>
<p:column>
<h:outputLabel value="Value: " />
</p:column>
<p:column>
<h:form id="sasInputTextForm" prependId="true">
<p:inputText id="sasInputText" value="#{cc.selectedValue}"
label="Value" binding="#{cc.sasInputText}" />
</h:form>
</p:column>
</p:row>
<p:row>
<p:column colspan="2" styleClass="searchAndResetColumn">
<h:form>
<p:commandButton value="Search" icon="ui-icon-search"
actionListener="#{cc.search}" />
<p:commandButton type="button" value="Reset"
icon="ui-icon-arrowrefresh-1-e" />
</h:form>
</p:column>
</p:row>
<p:row>
<p:column colspan="2">
<h:form>
<p:dataTable var="item" value="#{cc.data}">
<p:columns value="#{cc.columns}" var="column"
columnIndexVar="colIndex" sortBy="#{item[column.property]}"
filterBy="#{item[column.property]}">
<f:facet name="header">#{column.header}</f:facet>
#{item[column.property]}
</p:columns>
</p:dataTable>
</h:form>
</p:column>
</p:row>
</p:panelGrid>
<f:facet name="footer">
<p:commandButton type="button" value="OK" icon="ui-icon-check" />
<p:commandButton type="button" value="Cancel" icon="ui-icon-cancel"
onclick="searchAndSelect.hide();" />
</f:facet>
</p:dialog>
</composite:implementation>
</ui:component>
这是组件支持 bean (Lov.java):
@FacesComponent("lov")
public class Lov extends UIInput implements NamingContainer {
private List<ColumnModel> columns = new ArrayList<ColumnModel>();
private String definitionFile;
private String definitionName;
private String bean;
private String attribute;
private List<String> displayAttributes;
private UIInput lovInputText;
private UIInput sasInputText;
private UIComponent searchAndSelectDialog;
// Fields
// -------------------------------------------------------------------------------------
// Actions
// ------------------------------------------------------------------------------------
/**
* Returns the component family of {@link UINamingContainer}. (that's just
* required by composite component)
*/
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
/**
* Set the selected and available values of the day, month and year fields
* based on the model.
*/
@Override
public void encodeBegin(FacesContext context) throws IOException {
System.out.println("Called encodeBeing method...");
System.out.println("getValue: "+ getValue().toString());
setSelectedValue(getValue().toString());
definitionFile = getAttributeValue("definitionFile", null);
definitionName = getAttributeValue("definitionName", null);
try {
parseXml();
queryData();
} catch (Exception e) {
e.printStackTrace();
}
createDynamicColumns();
super.encodeBegin(context);
}
/**
* Returns the submitted value in dd-MM-yyyy format.
*/
@Override
public Object getSubmittedValue() {
System.out.println("====================================================");
System.out.println("getSubmittedValue method called...");
System.out.println("submittedValue: " + lovInputText.getSubmittedValue());
System.out.println("localValue: " +lovInputText.getLocalValue());
return lovInputText.getSubmittedValue();
}
/**
* Converts the submitted value to concrete {@link Date} instance.
*/
@Override
protected Object getConvertedValue(FacesContext context,
Object submittedValue) {
return super.getConvertedValue(context, submittedValue);
}
public void search(ActionEvent actionEvent) {
System.out.println("Search method called...");
try {
queryData();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Update the available days based on the selected month and year, if necessary.
*/
public void updateDialog(ActionEvent actionEvent) {
System.out.println("==========================================================");
System.out.println("updateDialog method called...");
System.out.println("getValue: "+getValue().toString());
setSelectedValue(getValue().toString());
/*FacesContext context = FacesContext.getCurrentInstance(); // Update dialog
context.getPartialViewContext().getRenderIds().add(searchAndSelectDialog.getClientId(context));*/
}
// Helpers
// ------------------------------------------------------------------------------------
/**
* Return specified attribute value or otherwise the specified default if
* it's null.
*/
@SuppressWarnings("unchecked")
private <T> T getAttributeValue(String key, T defaultValue) {
T value = (T) getAttributes().get(key);
return (value != null) ? value : defaultValue;
}
/**
* Create an integer array with values from specified begin to specified
* end, inclusive.
*/
private static Integer[] createIntegerArray(int begin, int end) {
int direction = (begin < end) ? 1 : (begin > end) ? -1 : 0;
int size = Math.abs(end - begin) + 1;
Integer[] array = new Integer[size];
for (int i = 0; i < size; i++) {
array[i] = begin + (i * direction);
}
return array;
}
protected void parseXml() throws ParserConfigurationException,
SAXException, IOException, XPathExpressionException,
URISyntaxException {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
DocumentBuilder builder = dbFactory.newDocumentBuilder();
ServletContext servletContext = (ServletContext) FacesContext
.getCurrentInstance().getExternalContext().getContext();
InputStream is = servletContext.getResourceAsStream(definitionFile);
Document doc = builder.parse(is);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile(String.format(
"/definitions/definition[@name='%s']/bean/@name",
definitionName));
Object result = expr.evaluate(doc, XPathConstants.STRING);
bean = result.toString();
setBean(bean);
System.out.println("bean: " + bean);
expr = xpath
.compile(String
.format("/definitions/definition[@name='%s']/attributes/attribute/@name",
definitionName));
result = expr.evaluate(doc, XPathConstants.STRING);
attribute = result.toString();
setAttribute(attribute);
System.out.println("attribute: " + attribute);
expr = xpath
.compile(String
.format("/definitions/definition[@name='%s']/displayAttributes/attribute",
definitionName));
result = expr.evaluate(doc, XPathConstants.NODESET);
displayAttributes = new ArrayList<String>();
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
NamedNodeMap attrs = nodes.item(i).getAttributes();
for (int j = 0; j < attrs.getLength(); j++) {
String nodeName = attrs.item(j).getNodeName();
if (nodeName.equalsIgnoreCase("name")) {
displayAttributes.add(attrs.item(j).getNodeValue());
}
}
}
setDisplayAttributes(displayAttributes);
System.out.println("displayAttributes: " + displayAttributes.toString());
}
protected void queryData() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException {
FilterableBean bean = (FilterableBean) findBean(getBean());
if (lovInputText != null) {
System.out.println("lovInputText exists");
}
System.out.println("queryData value: "+getValue().toString());
setData(bean.get(getSelectedValue()));
System.out.println("data: "+ getData().toString());
}
@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
FacesContext context = FacesContext.getCurrentInstance();
return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}
protected void createDynamicColumns() {
if (displayAttributes != null) {
columns.clear();
for (String displayAttribute : displayAttributes) {
String key = displayAttribute.trim();
columns.add(new ColumnModel(key.toUpperCase(), key));
}
}
}
// Getters/setters
// ----------------------------------------------------------------------------
@SuppressWarnings("rawtypes")
public List getData() {
return (List) getStateHelper().get("data");
}
@SuppressWarnings("rawtypes")
public void setData(List data) {
getStateHelper().put("data", data);
}
private String hello = "hello";
public String getHello() {
return hello;
}
public void setHello(String hello) {
this.hello = hello;
}
public List<ColumnModel> getColumns() {
return columns;
}
public String getSelectedValue() {
return (String) getStateHelper().get("selectedValue");
}
public void setSelectedValue(String selectedValue) {
getStateHelper().put("selectedValue", selectedValue);
}
public UIInput getLovInputText() {
return lovInputText;
}
public void setLovInputText(UIInput lovInputText) {
this.lovInputText = lovInputText;
}
public UIInput getSasInputText() {
return sasInputText;
}
public void setSasInputText(UIInput sasInputText) {
this.sasInputText = sasInputText;
}
public UIComponent getSearchAndSelectDialog() {
return searchAndSelectDialog;
}
public void setSearchAndSelectDialog(UIComponent searchAndSelectDialog) {
this.searchAndSelectDialog = searchAndSelectDialog;
}
public String getBean() {
return (String) getStateHelper().get("bean");
}
public void setBean(String bean) {
getStateHelper().put("bean", bean);
}
public String getAttribute() {
return (String) getStateHelper().get("attribute");
}
public void setAttribute(String attribute) {
getStateHelper().put("attribute", attribute);
}
@SuppressWarnings("unchecked")
public List<String> getDisplayAttributes() {
return (List<String>) getStateHelper().get("displayAttributes");
}
public void setDisplayAttributes(List<String> displayAttributes) {
getStateHelper().put("displayAttributes", displayAttributes);
}
static public class ColumnModel implements Serializable {
private String header;
private String property;
public ColumnModel(String header, String property) {
this.header = header;
this.property = property;
}
public String getHeader() {
return header;
}
public String getProperty() {
return property;
}
}
}
这是我使用该组件的方式:
<h:form>
<my:lov value="#{testBean.region}" definitionFile="/resources/xml/lov/definitions/country.xml" definitionName="LOV_Region"/>
<p:messages />
</h:form>
我正在关注 BalusC 的文章来创建这个组件。这是链接:
如何在自定义复合组件中使用对话框,该对话框将使用值更新并立即显示?