将 f:attribute 传递给复合实现中的 f:ajax 侦听器
Pass f:attribute to f:ajax listener inside composite implementation
我有以下复合组件(仅相关代码):
<cc:interface>
<cc:attribute name="message" type="com.virtuafisica.business.problemsmgmt.entity.Message" required="true" />
<cc:attribute name="notifiedListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)" />
</cc:interface>
<cc:implementation>
<h:selectBooleanCheckbox value="#{cc.attrs.message.notified}">
<f:attribute name="msg" value="#{cc.attrs.message}" />
<c:if test="#{cc.getValueExpression('notifiedListener') != null}">
<f:ajax event="change" listener="#{cc.attrs.notifiedListener}" />
</c:if>
</h:selectBooleanCheckbox>
</cc:implementation>
此组合是从 Facelet 调用的:
<my:message message="#{msg}" notifiedListener="#{problem.changeNotified}"/>
更改事件在支持 bean 中的处理方式如下:
public void changeNotified(AjaxBehaviorEvent event) {
Message message = (Message) event.getComponent().getAttributes().get("msg");
if (message == null) {
logger.log(Level.FINEST, "Null message!");
return;
}
....
}
问题是支持 bean 中的消息是 null
,尽管 event.getComponent()
是正确的(是 HTMLSelectBooleanCheckbox
)。
为什么没有设置属性?
谢谢大家
属性已设置(您可以通过确定 getValueExpression("msg")
没有 return null
来确认),但属性值只是评估 null
。延迟表达式会在您想要获取值的那一刻进行评估。因此,#{cc.attrs.message}
恰好在您在 ajax 侦听器方法中调用 get("msg")
的那一刻被评估。但是,此时 #{cc}
不存在于 EL 范围内的任何地方。
解决该技术问题的方法是手动将其放回 EL 范围(然后进行清理!)。
UIComponent component = event.getComponent();
UIComponent cc = UIComponent.getCompositeComponentParent(component);
Map<String, Object> requestScope = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
try {
requestScope.put("cc", cc);
Message message = (Message) component.getAttributes().get("msg");
}
finally {
requestScope.remove("cc");
}
另一种解决方法是直接从复合材料中获取它。
UIComponent cc = UIComponent.getCompositeComponentParent(event.getComponent());
Message message = (Message) cc.getAttributes().get("msg");
无论哪种方式,这都只是相当笨拙,因为支持 bean 不需要知道复合调用了 ajax 方法。简而言之,您遇到了设计问题。
考虑创建一个支持组件并从那里委托 ajax 调用,这样您就可以直接将 Message
作为方法参数传递。
@FacesComponent("yourCompositeName")
public class YourComposite extends UINamingContainer {
public void notifiedListener(AjaxBehaviorEvent event) {
MethodExpression notifiedListener = (MethodExpression) getAttributes().get("notifiedListener");
Message message = (Message) getAttributes().get("message");
notifiedListener.invoke(getFacesContext().getELContext(), new Object[] { message });
}
}
将其注册为 <cc:interface componentType>
,更改方法属性以采用 Message
参数并让 <f:ajax>
调用上述支持组件的侦听器方法,后者将依次委托到方法属性。
<cc:interface componentType="yourCompositeName">
<cc:attribute name="message" type="com.virtuafisica.business.problemsmgmt.entity.Message" required="true" />
<cc:attribute name="notifiedListener" method-signature="void listener(com.virtuafisica.business.problemsmgmt.entity.Message)" />
</cc:interface>
<cc:implementation>
<h:selectBooleanCheckbox value="#{cc.attrs.message.notified}">
<c:if test="#{cc.getValueExpression('notifiedListener') != null}">
<f:ajax listener="#{cc.notifiedListener}" />
</c:if>
</h:selectBooleanCheckbox>
</cc:implementation>
(注意:我删除了 event="change"
,因为那是 checkboxes/radiobuttons 的错误值,默认值已经是 valueChange
,这是正确的 - 它评估event="click"
checkboxes/radiobuttons)
现在你可以在 bean 中拥有这个。
public void changeNotified(Message message) {
// ...
}
我有以下复合组件(仅相关代码):
<cc:interface>
<cc:attribute name="message" type="com.virtuafisica.business.problemsmgmt.entity.Message" required="true" />
<cc:attribute name="notifiedListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)" />
</cc:interface>
<cc:implementation>
<h:selectBooleanCheckbox value="#{cc.attrs.message.notified}">
<f:attribute name="msg" value="#{cc.attrs.message}" />
<c:if test="#{cc.getValueExpression('notifiedListener') != null}">
<f:ajax event="change" listener="#{cc.attrs.notifiedListener}" />
</c:if>
</h:selectBooleanCheckbox>
</cc:implementation>
此组合是从 Facelet 调用的:
<my:message message="#{msg}" notifiedListener="#{problem.changeNotified}"/>
更改事件在支持 bean 中的处理方式如下:
public void changeNotified(AjaxBehaviorEvent event) {
Message message = (Message) event.getComponent().getAttributes().get("msg");
if (message == null) {
logger.log(Level.FINEST, "Null message!");
return;
}
....
}
问题是支持 bean 中的消息是 null
,尽管 event.getComponent()
是正确的(是 HTMLSelectBooleanCheckbox
)。
为什么没有设置属性?
谢谢大家
属性已设置(您可以通过确定 getValueExpression("msg")
没有 return null
来确认),但属性值只是评估 null
。延迟表达式会在您想要获取值的那一刻进行评估。因此,#{cc.attrs.message}
恰好在您在 ajax 侦听器方法中调用 get("msg")
的那一刻被评估。但是,此时 #{cc}
不存在于 EL 范围内的任何地方。
解决该技术问题的方法是手动将其放回 EL 范围(然后进行清理!)。
UIComponent component = event.getComponent();
UIComponent cc = UIComponent.getCompositeComponentParent(component);
Map<String, Object> requestScope = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
try {
requestScope.put("cc", cc);
Message message = (Message) component.getAttributes().get("msg");
}
finally {
requestScope.remove("cc");
}
另一种解决方法是直接从复合材料中获取它。
UIComponent cc = UIComponent.getCompositeComponentParent(event.getComponent());
Message message = (Message) cc.getAttributes().get("msg");
无论哪种方式,这都只是相当笨拙,因为支持 bean 不需要知道复合调用了 ajax 方法。简而言之,您遇到了设计问题。
考虑创建一个支持组件并从那里委托 ajax 调用,这样您就可以直接将 Message
作为方法参数传递。
@FacesComponent("yourCompositeName")
public class YourComposite extends UINamingContainer {
public void notifiedListener(AjaxBehaviorEvent event) {
MethodExpression notifiedListener = (MethodExpression) getAttributes().get("notifiedListener");
Message message = (Message) getAttributes().get("message");
notifiedListener.invoke(getFacesContext().getELContext(), new Object[] { message });
}
}
将其注册为 <cc:interface componentType>
,更改方法属性以采用 Message
参数并让 <f:ajax>
调用上述支持组件的侦听器方法,后者将依次委托到方法属性。
<cc:interface componentType="yourCompositeName">
<cc:attribute name="message" type="com.virtuafisica.business.problemsmgmt.entity.Message" required="true" />
<cc:attribute name="notifiedListener" method-signature="void listener(com.virtuafisica.business.problemsmgmt.entity.Message)" />
</cc:interface>
<cc:implementation>
<h:selectBooleanCheckbox value="#{cc.attrs.message.notified}">
<c:if test="#{cc.getValueExpression('notifiedListener') != null}">
<f:ajax listener="#{cc.notifiedListener}" />
</c:if>
</h:selectBooleanCheckbox>
</cc:implementation>
(注意:我删除了 event="change"
,因为那是 checkboxes/radiobuttons 的错误值,默认值已经是 valueChange
,这是正确的 - 它评估event="click"
checkboxes/radiobuttons)
现在你可以在 bean 中拥有这个。
public void changeNotified(Message message) {
// ...
}