h:从f:ajax请求导航后,h:form中的commandButton失败

时间:2013-09-24 09:13:11

标签: jsf jsf-2 primefaces

我正面临着一个邪恶的小问题,现在我已经躲过了近2天。我有一个p:treeTable组件,它用作导航和编辑分层数据结构的方法。树显示在左侧。通过选择树条目,用户选择要编辑的条目,然后在右侧的表格中显示该条目。还有一个用于在条目上添加新子节点的按钮。单击此按钮将创建所选节点的新子节点,右侧的表单将显示新节点。

树被实现为自定义标记。它有一个mode属性,允许我通过交换一个名为“mode”的绑定来重复使用它进行简单的导航或编辑。以下是树组件的摘录:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:composite="http://java.sun.com/jsf/composite"
    ...
    xmlns:ticker="http://java.sun.com/jsf/composite/components/ticker/">
    <h:body>
        <composite:interface>
            <composite:attribute name="mode" required="true" />
        </composite:interface>
    <composite:implementation>
            <h:form id="tickeruebersicht">
                <p:treeTable id="treetable" 
                    binding="#{treeNavigationController.treeTable}" 
                    value="#{treeNavigationController.root}" 
                    var="node" selectionMode="'single'}" 
                    selection="#{treeNavigationController.selection}">

                ...
                    <c:if test="#{cc.attrs.mode == 'editor'}">
                        <p:ajax event="select" 
                            listener="#{tickerUI.onNodeSelect}" 
                            update=":tickerEditForm"/>
            </c:if>

                 ...

                    <p:column style="width:5%" rendered="#{cc.attrs.mode == 'editor'}">
                        <h:commandLink title="new child node" 
                            action="#{tickerUI.createNewChildNode}"
                            styleClass="ui-icon ui-icon-plus" 
                            style="display:inline-block;">
                    <f:param name="parentNodeType" value="#{node.class.name}"/>
                            <f:param name="parentNodeID" value="#{node.id}"/>
                </h:commandLink>
                    </p:column>
                    ...
                </p:treeTable>
            </h:form>
    </composite:implementation>
    </h:body>
</html>

准备好捣碎的钻头。选择案例中的导航使用p:ajax。因为除非您在右侧页面上,否则具有id tickerEditForm的表单不可见,c:if控制包含ajax事件。添加新子节点时的导航使用h:commandLink工作。

以这种方式控制的表单如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<ui:composition template="template/master_layout.xhtml"
    xmlns="http://www.w3.org/1999/xhtml"
    ...
    xmlns:ticker="http://java.sun.com/jsf/composite/components/ticker">

    <ui:define name="leftcolumn">
        <h:panelGroup layout="block" id="leftColumn">
            <ticker:tickertree mode="editor" />
        </h:panelGroup>
    </ui:define>

    ...

    <ui:define name="content">

        <h:form id="tickerEditForm" acceptcharset="UTF-8">

            <ui:fragment rendered="#{tickerUI.ticker != null}">

                ...

                <span class="message">
                    <h:messages globalOnly="true" />
                </span>

                <ui:fragment rendered="#{tickerUI.neuerTicker}">
                ...
                </ui:fragment>

                <p class="inputLeft">
                    <h:outputLabel for="name">
                        <span>Name</span>
                    </h:outputLabel>
                                #{' '}
                    <h:inputText id="name" requiredMessage="Must enter name"
                                 value="#{tickerUI.ticker.label}" required="true">
                    </h:inputText>
                </p>

                ...

                <ui:fragment id="zusatzdaten">
                    <fieldset class="clear">
                        <h:panelGroup rendered="#{tickerUI.editComponentName != null}">
                            <ui:include src="#{tickerUI.editComponentName}" />
                        </h:panelGroup>
                    </fieldset>
                </ui:fragment>

                <div class="controls">
                    <span class="save"> 
                        <h:commandButton
                            action="#{tickerUI.saveAction}" value="speichern" />
                    </span> 
                    <span class="cancel"> 
                        <h:commandButton
                            action="#{tickerUI.createNewChildNode}" value="abbrechen" />
                    </span> 
                    <span class="delete"> 
                        <h:commandButton
                            action="#{tickerUI.deleteAction}" value="löschen"
                            disabled="#{not empty tickerUI.ticker.descendants or tickerUI.neuerTicker}" />
                    </span>
                </div>
            </ui:fragment>
        </h:form>
    </ui:define>

    <ui:debug />

</ui:composition>

最大的问题是,当使用h:commandLink导航到表单时,点击表单上的“保存”按钮会按预期调用操作方法。如果我使用p:ajax导航到表单,则表单的辅助bean是新构造的,当然数据丢失并且不会调用保存操作。两个支持bean(tickerUI和treeNavigationController)都是@ViewScoped。我试着去@SessionScoped看看是否有所作为,但没有区别。在Tomcat 6上使用Mojarra 2.2.3和Primefaces 3.5。

我和我在这里与JSF合作过的任何同事都无法弄清楚发生了什么。有人能看出问题所在吗?

0 个答案:

没有答案