【问题标题】:Pass f:attribute to f:ajax listener inside composite implementation将 f:attribute 传递给复合实现中的 f:ajax 侦听器
【发布时间】:2015-07-11 10:34:06
【问题描述】:

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

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

为什么没有设置属性?

谢谢大家

【问题讨论】:

    标签: jsf attributes jsf-2.2 composite-component


    【解决方案1】:

    属性已设置(您可以通过确定getValueExpression("msg") 没有返回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 });
        }
    
    }
    

    将其注册为&lt;cc:interface componentType&gt;,更改方法属性以获取Message 参数,并让&lt;f:ajax&gt; 调用上述支持组件上的侦听器方法,该方法将依次委托给方法属性。

    <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",因为这对于复选框/单选按钮来说是错误的,默认值是valueChange,它已经是正确的了——对于复选框/单选按钮,它的计算结果为event="click"

    现在你可以在 bean 中使用这个了。

    public void changeNotified(Message message) {
        // ...
    }  
    

    【讨论】:

    • 成功了,谢谢!!但是,为什么是 'cc.notifiedListener' 而不是 'cc.attrs.notifiedListener'?
    • 因为#{cc} 引用了YourComposite 实例。你想调用那里的方法,而不是传入的方法。
    猜你喜欢
    • 2014-07-22
    • 2015-12-07
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-05
    相关资源
    最近更新 更多