如果 JSF 复合组件与 f:ajax 标记一起使用,我如何在 EL 中进行测试?
How can I test, inside EL, if a JSF composite component is used with an f:ajax tag?
我的复合组件使用 clientBehavior 标签可选地支持 f:ajax 标签:
singleMultiSelect.xhtml
<cc:interface componentType="singleMultiSelect">
<!-- The initial list of objects -->
<cc:attribute name="list" type="java.util.List" required="true"/>
<!-- The selected objects -->
<cc:attribute name="selected" type="java.util.Collection" required="true"/>
<!-- whether to display the selectOneMenu (true) or selectManyBox (false) -->
<cc:attribute name="singleSelect" type="java.lang.Boolean"
required="false" default="true"/>
<cc:clientBehavior name="valueChange" event="valueChange"
targets="selectOneMenu selectManyListbox"/>
</cc:interface>
<cc:implementation>
<span id="#{cc.clientId}">
<ace:checkboxButton id="singleSelectChkBx"
value="#{cc.attrs.singleSelect}">
<ace:ajax render="#{cc.clientId}"/>
</ace:checkboxButton>
<h:selectOneMenu id="selectOneMenu"
rendered="#{cc.attrs.singleSelect}"
binding="#{cc.singleSelected}">
<f:selectItems value="#{cc.attrs.list}"/>
<!-- THIS PART IS NOT WORKING BECAUSE IT RETURNS 0
NO MATTER IF F:AJAX IS USED OR NOT -->
<c:if test="#{cc.getClientBehaviors().size() > 0}">
<f:ajax event="valueChange" execute="@this"
listener="#{cc.updateSelected}"/>
</c:if>
</h:selectOneMenu>
<h:selectManyListbox id="selectManyListbox"
rendered="#{! cc.attrs.singleSelect}"
value="#{cc.attrs.selected}">
<f:selectItems value="#{cc.attrs.list}"/>
</h:selectManyListbox>
</span>
</cc:implementation>
</ui:composition>
SingleMultiSelect.java
public class SingleMultiSelect extends UINamingContainer {
private UISelectOne singleSelected;
public SingleMultiSelect() {
super();
}
@Override
public void processUpdates(FacesContext context) {
super.processUpdates(context);
if (getAttributes().get("singleSelect") == Boolean.TRUE) {
HashSet selected = new HashSet();
if(singleSelected.getValue() != null) {
selected.add(singleSelected.getValue());
}
getValueExpression("selected").setValue(context.getELContext(), selected);
}
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
if (getAttributes().get("singleSelect") == Boolean.TRUE) {
Collection selected = (Collection) getAttributes().get("selected");
if (selected != null && !selected.isEmpty()) {
singleSelected.setValue(selected.iterator().next());
} else {
singleSelected.setValue(null);
}
}
super.encodeBegin(context);
}
public void updateSelected(AjaxBehaviorEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
if (getAttributes().get("singleSelect") == Boolean.TRUE) {
HashSet selected = new HashSet();
if(singleSelected.getValue() != null) {
selected.add(singleSelected.getValue());
}
getValueExpression("selected").setValue(context.getELContext(), selected);
}
}
/**
* @return the singleSelected
*/
public UISelectOne getSingleSelected() {
return singleSelected;
}
/**
* @param singleSelected the singleSelected to set
*/
public void setSingleSelected(UISelectOne singleSelected) {
this.singleSelected = singleSelected;
}
}
我如何在 EL 中测试客户端是否实际使用 ajax。例如:
<mylib:mycomp />
对
<mylib:mycomp>
<f:ajax event="valueChange"/>
</mylib:mycomp>
在代码中,您可以看到我尝试使用 cc.getClientBehaviors().size() 来查看是否填充了客户端行为,但它总是 returns 0.
您可以检查复合组件代码内部,例如这些属性。
1) 如果插入了特定行为
#{empty cc.getClientBehaviors().get("valueChange")}
2) 或任何
#{cc.getClientBehaviors().size() > 0}
JSF 组件必须实现 ClientBehaviorHolder 接口并且 getEventNames() 方法需要重写为 return支持的事件列表:
SingleMultiSelect.java:
public class SingleMultiSelect extends UINamingContainer implements ClientBehaviorHolder {
...
@Override
public Collection<String> getEventNames() {
Collection<String> eventNames = new HashSet<>();
eventNames.add("valueChange");
return eventNames;
}
...
}
一旦完成,@rvillar 的回答就奏效了:
1) 如果插入了特定行为
#{empty cc.getClientBehaviors().get("valueChange")}
2) 或任何
#{cc.getClientBehaviors().size() > 0}
我的复合组件使用 clientBehavior 标签可选地支持 f:ajax 标签:
singleMultiSelect.xhtml
<cc:interface componentType="singleMultiSelect">
<!-- The initial list of objects -->
<cc:attribute name="list" type="java.util.List" required="true"/>
<!-- The selected objects -->
<cc:attribute name="selected" type="java.util.Collection" required="true"/>
<!-- whether to display the selectOneMenu (true) or selectManyBox (false) -->
<cc:attribute name="singleSelect" type="java.lang.Boolean"
required="false" default="true"/>
<cc:clientBehavior name="valueChange" event="valueChange"
targets="selectOneMenu selectManyListbox"/>
</cc:interface>
<cc:implementation>
<span id="#{cc.clientId}">
<ace:checkboxButton id="singleSelectChkBx"
value="#{cc.attrs.singleSelect}">
<ace:ajax render="#{cc.clientId}"/>
</ace:checkboxButton>
<h:selectOneMenu id="selectOneMenu"
rendered="#{cc.attrs.singleSelect}"
binding="#{cc.singleSelected}">
<f:selectItems value="#{cc.attrs.list}"/>
<!-- THIS PART IS NOT WORKING BECAUSE IT RETURNS 0
NO MATTER IF F:AJAX IS USED OR NOT -->
<c:if test="#{cc.getClientBehaviors().size() > 0}">
<f:ajax event="valueChange" execute="@this"
listener="#{cc.updateSelected}"/>
</c:if>
</h:selectOneMenu>
<h:selectManyListbox id="selectManyListbox"
rendered="#{! cc.attrs.singleSelect}"
value="#{cc.attrs.selected}">
<f:selectItems value="#{cc.attrs.list}"/>
</h:selectManyListbox>
</span>
</cc:implementation>
</ui:composition>
SingleMultiSelect.java
public class SingleMultiSelect extends UINamingContainer {
private UISelectOne singleSelected;
public SingleMultiSelect() {
super();
}
@Override
public void processUpdates(FacesContext context) {
super.processUpdates(context);
if (getAttributes().get("singleSelect") == Boolean.TRUE) {
HashSet selected = new HashSet();
if(singleSelected.getValue() != null) {
selected.add(singleSelected.getValue());
}
getValueExpression("selected").setValue(context.getELContext(), selected);
}
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
if (getAttributes().get("singleSelect") == Boolean.TRUE) {
Collection selected = (Collection) getAttributes().get("selected");
if (selected != null && !selected.isEmpty()) {
singleSelected.setValue(selected.iterator().next());
} else {
singleSelected.setValue(null);
}
}
super.encodeBegin(context);
}
public void updateSelected(AjaxBehaviorEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
if (getAttributes().get("singleSelect") == Boolean.TRUE) {
HashSet selected = new HashSet();
if(singleSelected.getValue() != null) {
selected.add(singleSelected.getValue());
}
getValueExpression("selected").setValue(context.getELContext(), selected);
}
}
/**
* @return the singleSelected
*/
public UISelectOne getSingleSelected() {
return singleSelected;
}
/**
* @param singleSelected the singleSelected to set
*/
public void setSingleSelected(UISelectOne singleSelected) {
this.singleSelected = singleSelected;
}
}
我如何在 EL 中测试客户端是否实际使用 ajax。例如:
<mylib:mycomp />
对
<mylib:mycomp>
<f:ajax event="valueChange"/>
</mylib:mycomp>
在代码中,您可以看到我尝试使用 cc.getClientBehaviors().size() 来查看是否填充了客户端行为,但它总是 returns 0.
您可以检查复合组件代码内部,例如这些属性。
1) 如果插入了特定行为
#{empty cc.getClientBehaviors().get("valueChange")}
2) 或任何
#{cc.getClientBehaviors().size() > 0}
JSF 组件必须实现 ClientBehaviorHolder 接口并且 getEventNames() 方法需要重写为 return支持的事件列表:
SingleMultiSelect.java:
public class SingleMultiSelect extends UINamingContainer implements ClientBehaviorHolder {
...
@Override
public Collection<String> getEventNames() {
Collection<String> eventNames = new HashSet<>();
eventNames.add("valueChange");
return eventNames;
}
...
}
一旦完成,@rvillar 的回答就奏效了:
1) 如果插入了特定行为
#{empty cc.getClientBehaviors().get("valueChange")}
2) 或任何
#{cc.getClientBehaviors().size() > 0}