通过 Ajax 错误地刷新列表的 JSF

JSF refreshing list via Ajax incorrectly

我正在尝试将一些功能从 JQuery 迁移到 JSF,但我得到了奇怪的结果。

基本上它是一个页面,您可以在其中导航 links(想象成 Web 上的 Windows 资源管理器)。文件夹有 link 而叶子没有。为了构造它,它使用了 private List<Element> list;,它会相应地刷新。因此,当用户单击 "folder" 时,将使用该文件夹的内容创建一个新的 list

问题是我得到了奇怪的结果。有时我导航 link 并且它被正确刷新,但在某些情况下它的行为就像页面被重新加载(但它没有)并且 list 被重置为其初始值(?)。例如,我导航到 "name2" 并得到正确的东西。但是后来我转到 "name2b",我得到的不是叶子,而是 "name1"、"name2" 和 "name3",它们仅在 init() 方法中设置。我不知道这是怎么发生的,但探索源代码似乎 c:foreach 结构与 id 混淆并且页面中呈现了旧 ID(请注意,我已经尝试 ui:repeat同样错误的结果)。

我该如何解决这个问题?

这是简化代码:

<f:metadata>
   <f:viewAction action="#{controller.init}" />
</f:metadata>
...
<h:panelGroup id="visor" layout="block">
            <ul>
                <c:forEach items="#{controller.list}" var="element">
                    <li>
                        <ui:fragment rendered="#{element.folder}">
                            <h:form>
                                <h:commandButton action="#{controller.navigate(element.name)}" type="submit" value="#{element.name}" >
                                    <f:ajax render="visor" execute="@this" />
                                </h:commandButton>
                            </h:form>
                        </ui:fragment>
                        <ui:fragment rendered="#{not element.folder}">
                            <span>#{element.name}</span>
                        </ui:fragment>
                    </li>
                </c:forEach>
            </ul>
        </h:panelGroup>

和控制器

@Named(value = "controller")
@ViewScoped
public class MyController implements Serializable {

private List<Element> list;

public void init() { //Called when loading the page
    list = new ArrayList<>();
    Element e1 = new Element("name1", true); //name and isFolder?
    Element e2 = new Element("name2", true);
    Element e3 = new Element("name3", true);
    list.add(e1);
    list.add(e2);
    list.add(e3);
}

public void navigate(String name) {
    list = new ArrayList<>();
    if (name.equals("name1")) {
         Element e1 = new Element("name1a", true);
         Element e2 = new Element("name1b", true);
         Element e3 = new Element("name1c", true);
         list.add(e1); list.add(e2); list.add(e3);
    } else if (name.equals("name2")) {
        Element e1 = new Element("name2a", true);
         Element e2 = new Element("name2b", true);
         Element e3 = new Element("name2c", true);
         list.add(e1); list.add(e2); list.add(e3);
    } else {
        Element e1 = new Element("leaf1", false);
         Element e2 = new Element("leaf2", false);
         list.add(e1); list.add(e2);
    }
}
//....

编辑

我的问题好像描述的是in here

我必须调查一下 是否可以为这个主题带来一些启发。

显然它是一个带有基本 JSF 的 that my structure cannot be dynamically updated in JSF. The solution I have to make is to use a h:datatable instead of a <ul> list (this is one thing I really dislike of JSF, but I am not sure how to render a list - 而不是我可以动态更新的 table。

Ajax render 属性必须指定 form id。

<h:form id="visor">
      <h:dataTable value="#{controller.list}" var="element">
                    <h:column>
                        ....
                        <h:commandButton action=.... >
                          <f:ajax render="visor" execute="@this" />
                        </h:commandButton>
                        ....
                    </h:column>
      </h:dataTable>
</h:form>

编辑UL 也有效,只要我渲染表单并且表单包含所有内容