关于条件渲染元素内的 jsf:ajax 侦听器不起作用

ajax listener inside conditionally rendered element not working

本问题已经有最佳答案,请猛点这里访问。

这是我的问题的测试用例:

测试豆:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@ManagedBean
@ViewScoped
public class TestBean implements Serializable {
    private static final long serialVersionUID = -2329929006490721388L;

    private List<TestObject> testObjects;
    private int selectedId;

    public TestBean(){
        List<TestObject> to = new ArrayList<TestObject>();
        for(int i=0; i<10; i++){
            TestObject o = new TestObject(i,"object-"+i);
            to.add(o);
        }
        this.setTestObjects(to);
    }

    public void testAjaxListener(int id){
        System.out.println("testAjaxListener("+id+")");
        this.setSelectedId(id);
    }

    //+getters/setters
}

测试对象

1
2
3
4
5
6
7
8
9
10
11
public class TestObject {
    private int id;
    private String name;

    public TestObject(int id, String name){
        this.setId(id);
        this.setName(name);
    }

    //+getters/setters
}

测试.xhtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">
<h:head></h:head>
<h:body>
    <h:form id="testForm">
        <h:panelGroup rendered="#{param['view'] eq 'test'}">
            DataTable
            <h:dataTable var="o" value="#{testBean.testObjects}">
                <h:column>
                    <h:commandLink value="#{o.name}" actionListener="#{testBean.testAjaxListener(o.id)}">
                        <f:ajax
                            render=":testForm:outputTest"
                        />
                    </h:commandLink>
                </h:column>
            </h:dataTable>
            output
            <h:outputText id="outputTest" value="#{testBean.selectedId}" />
        </h:panelGroup>
    </h:form>
</h:body>
</html>

问题是,actionListener 不会触发(我正在使用 System.out.print 进行检查,如您所见)。当我从 panelGroup 中删除条件渲染时它工作正常,所以我认为这是问题所在 - 但我该如何解决?
我已经阅读了这些主题:
h:commandLink / h:commandButton 未被调用,
f:ajax 在有条件呈现的自定义标记内 - 未调用支持 bean 方法
还有更多,但它并没有解决我的问题:(

请帮忙


这是因为 #{param['view'] eq 'test'} 在 JSF 忙于处理 ajax 提交时没有评估 true。然后它还会再次查询 rendereddisabledreadonly 属性,以防止被黑客入侵的请求。 JSF 即不包括 <h:form> 生成的 <form action> URL 中的请求参数。这与未调用或未更新输入值的 commandButton/commandLink/ajax 操作/侦听器方法的第 5 点相匹配。

有几种方法可以解决这个问题。

  • 通过 <f:viewParam>.

    将其设置为视图范围 bean 的属性

    1
    2
    3
    4
    5
    <f:metadata>
        <f:viewParam name="view" value="#{testBean.view}" />
    </f:metadata>
    ...
    <h:panelGroup rendered="#{testBean.view eq 'test'}">

  • 通过<f:param>手动保留参数(你需要把它放在每个提交动作中!):

    1
    2
    3
    4
    <h:commandLink ...>
        <f:param name="view" value="#{param.view}" />
        ...
    </h:commandLink>
  • <h:form> 替换为 OmniFaces <o:form>,它能够告诉 JSF 它必须将表单提交到包含请求参数的 URL:

    1
    2
    3
    <o:form includeRequestParams="true">
        ...
    </o:form>
  • 也可以看看:

    • 在 JSF 表单提交上保留 GET 请求查询字符串参数