1

我正面临一个棘手的小问题,这已经困扰我近 2 天了。我得到了 ap: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>

重要的部分都准备好了。选择案例中的导航使用 ap:ajax 工作。因为除非您在正确的页面上,否则 ID 为 tickerEditForm 的表单是不可见的,因此 c:if 控制 ajax 事件的包含。添加新子节点时的导航使用 ah: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 一起工作的任何同事都无法弄清楚发生了什么。有人能看出问题所在吗?

4

0 回答 0