Jsf 在复合实现内将f:attribute传递给f:ajax侦听器

Jsf 在复合实现内将f:attribute传递给f:ajax侦听器,jsf,attributes,jsf-2.2,composite-component,Jsf,Attributes,Jsf 2.2,Composite Component,我有以下复合组件(仅相关代码): 问题是,尽管事件.getComponent()是正确的消息(是htmlselectbooleancheboxbox),但支持bean中的消息是null 为什么不设置属性 谢谢大家属性已设置(您可以通过确定getValueExpression(“msg”)没有返回null),来确认属性值,但属性值仅计算为null。延迟表达式的计算时间正好是您想要获取值的时间。因此,{cc.attrs.message}是在ajax侦听器方法中调用get(“msg”)的那一刻计算的。

我有以下复合组件(仅相关代码):

问题是,尽管
事件.getComponent()
是正确的消息(是
htmlselectbooleancheboxbox
),但支持bean中的消息是
null

为什么不设置属性

谢谢大家

属性已设置(您可以通过确定
getValueExpression(“msg”)
没有返回
null
),来确认属性值,但属性值仅计算为
null
。延迟表达式的计算时间正好是您想要获取值的时间。因此,
{cc.attrs.message}
是在ajax侦听器方法中调用
get(“msg”)
的那一刻计算的。但是,此时,
{cc}
在EL范围内的任何地方都不存在

解决这一技术问题的方法是手动将其放回EL范围(以及随后的清理!)

无论哪种方式,这都是相当笨拙的,因为支持bean不需要知道ajax方法是由组合调用的。简单地说,你有一个设计问题

考虑创建一个支持组件并从那里委派ajax调用,这样您就可以直接将
消息
作为方法参数传递

@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 });
    }

}
将其注册为
,更改method属性以获取
Message
参数,并让
调用上述支持组件上的侦听器方法,这将反过来委托给method属性

<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>

这很有效,谢谢!!但是,为什么是“cc.notifiedListener”而不是“cc.attrs.notifiedListener”?因为
{cc}
引用了
YourComposite
实例。您希望调用其中的方法,而不是传入的方法。
public void changeNotified(AjaxBehaviorEvent event) {
    Message message = (Message) event.getComponent().getAttributes().get("msg");
        if (message == null) {
            logger.log(Level.FINEST, "Null message!");
            return;
        }
        ....
    }
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");
@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="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>
public void changeNotified(Message message) {
    // ...
}