ajax 侦听器不起作用

ajax listener inside conditionally rendered element not working

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

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

测试豆:

@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

}public class TestObject {

  private int id;

  private String name;



  public TestObject(int id, String name){

    this.setId(id);

    this.setName(name);

  }



  //+getters/setters

}<?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><f:metadata>

  <f:viewParam name="view" value="#{testBean.view}" />

</f:metadata>

...

<h:panelGroup rendered="#{testBean.view eq 'test'}"><h:commandLink ...>

  <f:param name="view" value="#{param.view}" />

  ...

</h:commandLink><o:form includeRequestParams="true">

  ...

</o:form>

测试对象

@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

}public class TestObject {

  private int id;

  private String name;



  public TestObject(int id, String name){

    this.setId(id);

    this.setName(name);

  }



  //+getters/setters

}<?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><f:metadata>

  <f:viewParam name="view" value="#{testBean.view}" />

</f:metadata>

...

<h:panelGroup rendered="#{testBean.view eq 'test'}"><h:commandLink ...>

  <f:param name="view" value="#{param.view}" />

  ...

</h:commandLink><o:form includeRequestParams="true">

  ...

</o:form>

测试.xhtml:

@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

}public class TestObject {

  private int id;

  private String name;



  public TestObject(int id, String name){

    this.setId(id);

    this.setName(name);

  }



  //+getters/setters

}<?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><f:metadata>

  <f:viewParam name="view" value="#{testBean.view}" />

</f:metadata>

...

<h:panelGroup rendered="#{testBean.view eq 'test'}"><h:commandLink ...>

  <f:param name="view" value="#{param.view}" />

  ...

</h:commandLink><o:form includeRequestParams="true">

  ...

</o:form>

问题是,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 的属性

    @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
    
    }public class TestObject {
    
      private int id;
    
      private String name;
    
    
    
      public TestObject(int id, String name){
    
        this.setId(id);
    
        this.setName(name);
    
      }
    
    
    
      //+getters/setters
    
    }<?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><f:metadata>
    
      <f:viewParam name="view" value="#{testBean.view}" />
    
    </f:metadata>
    
    ...
    
    <h:panelGroup rendered="#{testBean.view eq 'test'}"><h:commandLink ...>
    
      <f:param name="view" value="#{param.view}" />
    
      ...
    
    </h:commandLink><o:form includeRequestParams="true">
    
      ...
    
    </o:form>
  • 通过<f:param>手动保留参数(你需要把它放在每个提交动作中!):

    @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
    
    }public class TestObject {
    
      private int id;
    
      private String name;
    
    
    
      public TestObject(int id, String name){
    
        this.setId(id);
    
        this.setName(name);
    
      }
    
    
    
      //+getters/setters
    
    }<?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><f:metadata>
    
      <f:viewParam name="view" value="#{testBean.view}" />
    
    </f:metadata>
    
    ...
    
    <h:panelGroup rendered="#{testBean.view eq 'test'}"><h:commandLink ...>
    
      <f:param name="view" value="#{param.view}" />
    
      ...
    
    </h:commandLink><o:form includeRequestParams="true">
    
      ...
    
    </o:form>
  • <h:form> 替换为 OmniFaces <o:form>,它能够告诉 JSF 它必须将表单提交到包含请求参数的 URL:

    @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
    
    }public class TestObject {
    
      private int id;
    
      private String name;
    
    
    
      public TestObject(int id, String name){
    
        this.setId(id);
    
        this.setName(name);
    
      }
    
    
    
      //+getters/setters
    
    }<?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><f:metadata>
    
      <f:viewParam name="view" value="#{testBean.view}" />
    
    </f:metadata>
    
    ...
    
    <h:panelGroup rendered="#{testBean.view eq 'test'}"><h:commandLink ...>
    
      <f:param name="view" value="#{param.view}" />
    
      ...
    
    </h:commandLink><o:form includeRequestParams="true">
    
      ...
    
    </o:form>
  • 也可以看看:

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

相关推荐

  • Spring部署设置openshift

    Springdeploymentsettingsopenshift我有一个问题让我抓狂了三天。我根据OpenShift帐户上的教程部署了spring-eap6-quickstart代码。我已配置调试选项,并且已将Eclipse工作区与OpehShift服务器同步-服务器上的一切工作正常,但在Eclipse中出现无法消除的错误。我有这个错误:cvc-complex-type.2.4.a:Invali…
    2025-04-161
  • 检查Java中正则表达式中模式的第n次出现

    CheckfornthoccurrenceofpatterninregularexpressioninJava本问题已经有最佳答案,请猛点这里访问。我想使用Java正则表达式检查输入字符串中特定模式的第n次出现。你能建议怎么做吗?这应该可以工作:MatchResultfindNthOccurance(intn,Patternp,CharSequencesrc){Matcherm=p.matcher…
    2025-04-161
  • 如何让 JTable 停留在已编辑的单元格上

    HowtohaveJTablestayingontheeditedcell如果有人编辑JTable的单元格内容并按Enter,则内容会被修改并且表格选择会移动到下一行。是否可以禁止JTable在单元格编辑后转到下一行?原因是我的程序使用ListSelectionListener在单元格选择上同步了其他一些小部件,并且我不想在编辑当前单元格后选择下一行。Enter的默认绑定是名为selectNext…
    2025-04-161
  • Weblogic 12c 部署

    Weblogic12cdeploy我正在尝试将我的应用程序从Tomcat迁移到Weblogic12.2.1.3.0。我能够毫无错误地部署应用程序,但我遇到了与持久性提供程序相关的运行时错误。这是堆栈跟踪:javax.validation.ValidationException:CalltoTraversableResolver.isReachable()threwanexceptionatorg.…
    2025-04-161
  • Resteasy Content-Type 默认值

    ResteasyContent-Typedefaults我正在使用Resteasy编写一个可以返回JSON和XML的应用程序,但可以选择默认为XML。这是我的方法:@GET@Path("/content")@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})publicStringcontentListRequestXm…
    2025-04-161
  • 代码不会停止运行,在 Java 中

    thecodedoesn'tstoprunning,inJava我正在用Java解决项目Euler中的问题10,即"Thesumoftheprimesbelow10is2+3+5+7=17.Findthesumofalltheprimesbelowtwomillion."我的代码是packageprojecteuler_1;importjava.math.BigInteger;importjava…
    2025-04-161
  • Out of memory java heap space

    Outofmemoryjavaheapspace我正在尝试将大量文件从服务器发送到多个客户端。当我尝试发送大小为700mb的文件时,它显示了"OutOfMemoryjavaheapspace"错误。我正在使用Netbeans7.1.2版本。我还在属性中尝试了VMoption。但仍然发生同样的错误。我认为阅读整个文件存在一些问题。下面的代码最多可用于300mb。请给我一些建议。提前致谢publicc…
    2025-04-161
  • Log4j 记录到共享日志文件

    Log4jLoggingtoaSharedLogFile有没有办法将log4j日志记录事件写入也被其他应用程序写入的日志文件。其他应用程序可以是非Java应用程序。有什么缺点?锁定问题?格式化?Log4j有一个SocketAppender,它将向服务发送事件,您可以自己实现或使用与Log4j捆绑的简单实现。它还支持syslogd和Windows事件日志,这对于尝试将日志输出与来自非Java应用程序…
    2025-04-161