JSF/Primefaces - p:ajax元素中的ui:param

5

我正在使用Java EE 6编写应用程序,并使用Primefaces 3.4.1为用户界面。

我有类似以下的内容。

genericPage.xhtml

<ui:composition template="mainApplicationTemplate.xhtml" [...]>
    <p:tabView id="tabView" dynamic="false"cache="false">
        <p:tab id="tab1" title="Tab 1">
            <h:form id="form1">
                ...
            </h:form>
        </p:tab>
        <p:tab id="tab1" title="Tab 1">
            <h:form id="form2">
                ...
            </h:form>
        </p:tab>
    </p:tabView>
<ui:composition >

child1.xmtml

<ui:composition template="genericPage.xhtml" ...>
    <ui:param name="actionBean" value="#{actionBeanA}"/>
</ui:compisition>

child2.xmtml

<ui:composition template="genericPage.xhtml" ...>
    <ui:param name="actionBean" value="#{actionBeanB}"/>
</ui:compisition>

这背后的思路是,child1.xhtml和child2.xhtml共享相同的jsf代码,都包含在genericPage.xhtml中,但它们具有不同的后端bean(由“actionBean”参数化)。
到目前为止这工作得很好。当我把ui参数放在元素中时,它变得复杂了。
从后端bean中,我需要编程方式更新活动选项卡,而保留其他选项卡不受影响。为了做到这一点,我需要在action bean中存储活动选项卡。当发生某些外部事件时,action bean会更新活动选项卡。
请注意,由于其他一些因素:
- 我不能在tabView中设置dynamic="true" - 我不能在tabView周围有一个全局表单,因此不能使用'activeIndex'属性(我在应用程序的其他部分中正在使用它)来管理活动选项卡。
我想做什么
为了解决这个问题,我想使用tabView元素的tabChange事件:
<p:tabView id="tabView" dynamic="false"cache="false">
        <p:ajax event="tabChange" listener="#{actionBean.listen}"
        <p:tab id="tab1" title="Tab 1">
            <h:form id="form1">
                ...
            </h:form>
        </p:tab>
        <p:tab id="tab1" title="Tab 1">
            <h:form id="form2">
                ...
            </h:form>
        </p:tab>
    </p:tabView>

操作Bean

@Named
@WindowScoped
public class ActionBeanA implements Serializable{
    public void listen(TabChangeEvent event){
        ...
    }

}

无法正常工作的原因

当我这么做时,出现了错误

Target Unreachable, identifier 'actionBean' resolved to null: javax.el.PropertyNotFoundException: Target Unreachable, identifier 'actionBean' resolved to null

这似乎表明<p:ajax>元素没有传递action bean,因此不知道actionBean是什么。
但是,如果我更改侦听器方法的签名,如下所示:
<p:ajax event="tabChange" listener="#{actionBean.listen(anything)}"

并将后端的bean更改为以下内容:

public void listen(TabChangeEvent event){
    System.out.println(event.toString());
}

我这样做,就不会出现“目标不可达”的错误,但是在listen方法中却会出现空指针异常(因为我没有给“anything”赋值)。这表明在此情况下,<p:ajax/> 元素知道 actionBean 是什么,并成功调用了bean中的方法。

问题

我该如何解决这个问题?我想在选项卡更改事件上,将新活动选项卡发送到我的后端bean。


1
你不需要传递任何参数到 void listen(TabChangeEvent event) 方法中。只需保留该方法的签名并使用 listener="#{actionBean.listen}",框架会自动为您传递事件。 - Elias Dorneles
1
正如我所解释的,当我执行listener="#{actionBean.listen}"时,会出现“目标不可达”的错误。 - phoenix7360
好的,我明白你的意思。然而,实际上我从未更改后端方法的签名,它一直是 void listen(TabChangeEvent event)。我所说的是在前端更改调用的签名:listener="#{actionBean.listen}"listener="#{actionBean.listen(something)}"。我意识到我不应该自己传递事件,但由于似乎存在一个错误,我只是试图找到解决方法。 - phoenix7360
那么如果没有参数调用它,结果是什么? - Aritz
看起来你正在做所有这些控制选定哪个选项卡以便更新它的事情,为什么不直接更新你所在的表单呢?那样应该可以保持你所选的选项卡。 - Aritz
显示剩余2条评论
2个回答

6
我也遇到了这个问题,并在Primefaces问题跟踪器中找到了解决方案:在帖子#20中找到的解决方案 总之,这是Primefaces中已知的问题。半修复方法可以在3.4.2版本中找到,并需要对代码进行一些更改。目前您有:
public void listen(TabChangeEvent event){
    System.out.println(event.toString());
}

这是错误的写法,你需要修改你的代码为:

public void listen(AjaxBehaviorEvent event){
    System.out.println(event.toString());
}

如果您需要使用特定的 TabChangeEvent 方法,则需要进行强制类型转换:(TabChangeEvent)event

它在问题跟踪器中具有已修复的状态,因此可能需要将其作为永久解决方案。


-1

值表达式处理和方法表达式处理之间有所不同。对于后者,您需要稍后在Facelet上下文中可用参数。

要将参数的值包含在facelet上下文中,只需将参数值定义放在<f:metadata>标记内即可。

此外,请注意<f:metadata>标记应始终是<f:view>标记的直接子级,因此我会这样做:

template.xhtml

<f:view ....>
    <ui:insert name="metadata"/>
    ....
</f:view>

childPage.xhtml

<ui:composition template="/WEB-INF/template.xhtml">
    <ui:define name="metadata">
        <f:metadata>
            <ui:param name="actionBean" value="#{actionBeanA}"
        </f:metadata>
    </ui:define>
</ui:composition>

完成此操作后,您可以在template.xhtml中以原始方式使用监听器属性,无需解决任何问题,您的方法将始终使用适当的事件类型参数进行调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接