JSF ui:repeat 被 ui:include 包裹在 h:panelGroup 中,带有条件渲染...满嘴 [英] JSF ui:repeat included by ui:include wrapped in h:panelGroup with conditional rendering... A mouthfull

查看:34
本文介绍了JSF ui:repeat 被 ui:include 包裹在 h:panelGroup 中,带有条件渲染...满嘴的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

原始问题如下,但我想出了一个更简单的例子来演示这个问题,并认为它应该放在顶部.

Original question is below, but as I have come up with a more minimal example to demonstrate this problem, and figured it should go at the top.

无论如何,似乎 ui:repeat 标签在检查父元素是否实际呈现之前已被处理.要重新创建它,这里是 facelet (minimalTest.xhtml):

Anyway, it appears that ui:repeat tags are processed before checking to see if parent elements are actually rendered. To recreate this, here is the facelet (minimalTest.xhtml):

<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>
  <title>Test JSF &lt;ui:repeat&gt; inside &lt;h:panelGroup rendered=&quot;false&quot;&gt;</title>
</h:head>
<h:body>
  <h:form>
    <h1>Testing</h1>
    <h:panelGroup rendered="false">
      <span>#{minimalTestBean.alsoThrowsException}</span>
      <ul>
        <ui:repeat value="#{minimalTestBean.throwsException}" var="item">
          <li>#{item}</li>
        </ui:repeat>
      </ul>
    </h:panelGroup>
  </h:form>
</h:body>
</html>

使用这个 bean (MinimalTestBean.java):

With using this bean (MinimalTestBean.java):

package com.lucastheisen.beans;


import java.io.Serializable;
import java.util.List;


import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;


@ManagedBean
@ViewScoped
public class MinimalTestBean implements Serializable {
    private static final long serialVersionUID = 9045030165653014015L;

    public String getAlsoThrowsException() {
        throw new RuntimeException( "rendered is false so this shouldnt get called either" );
    }

    public List<String> getThrowsException() {
        throw new RuntimeException( "rendered is false so this shouldnt get called" );
    }
}

从这个例子你可以看到包含 ui:repeath:panelGroup 被静态设置为 rendered=false会假设这意味着该 h:panelGroup 内的任何 EL 表达式都不会被执行.EL 表达式只是调用引发 RuntimeException 的 getter.然而, ui:repeat 实际上是为其列表调用 getter,从而导致异常,即使它一开始就不应该被渲染.如果您注释掉 ui:repeat 元素,则不会抛出异常(即使其他 EL 表达式仍保留在 h:panelGroup 中),正如我所期望的那样.

From this example you can see that the h:panelGroup that contains the ui:repeat is statically set to rendered=false which I would assume would mean that none of the EL expressions inside of that h:panelGroup would get executed. The EL expressions just call getters which throw a RuntimeException. However, the ui:repeat is actually calling the getter for its list thus causing the exception even though it should not be getting rendered in the first place. If you comment out the ui:repeat element, no exceptions get thrown (even though the other EL expression remains in the h:panelGroup) as I would expect.

在 stackoverflow 上阅读其他问题让我相信这可能与经常提到的问题有关 鸡/蛋问题,但我不确定具体原因,也不知道该怎么做.我想将 PARTIAL_STATE_SAVING 设置为 false 可能会有所帮助,但希望避免内存影响.

Reading other questions here on stackoverflow leads me to believe that is likely related to the oft-referred-to chicken/egg issue, but I am not sure exactly why, nor what to do about it. I imagine setting the PARTIAL_STATE_SAVING to false might help, but would like to avoid the memory implications.

----原始问题----

---- ORIGINAL QUESTION ----

基本上,我有一个页面,它使用 <h:panelGroup rendering="#{modeXXX}"> 有条件地呈现部分,包裹在 <ui:include src="pageXXX.xhtml"/> (根据这个 回答).问题是,如果其中一个 pageXXX.xhtml 有一个 <ui:repeat> 在其中,它似乎得到处理,即使包含 <h:panelGroup>code> 有 rendered=false.这是一个问题,因为我的某些部分依赖于已被其他部分初始化,而这些部分应该在它们之前访问.为什么会处理包含的 pageXXX.xhtml?

Basically, I have a page that conditionally renders sections using <h:panelGroup rendered="#{modeXXX}"> wrapped around <ui:include src="pageXXX.xhtml" /> (per this answer). The problem is that if one of the pageXXX.xhtml has a <ui:repeat> inside of it, it seems to get processed even when the containing <h:panelGroup> has rendered=false. This is a problem because some of my sections rely on having been initialized by other sections that should be visited before them. Why is the included pageXXX.xhtml getting processed?

这是一个令人痛苦的错误,而且很难归结为一个小例子,但这是我可以构建的最简单的案例来证明这个问题.首先是一个基本页面:

This is a painful bug and incredibly hard to boil down to a small example, but here is the most minimal case I could build that demonstrates the issue. First a base page:

<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>
  <title>Test JSF &lt;ui:include&gt;</title>
</h:head>
<h:body>
  <h:form>
    <h1>#{testBean.title}</h1>
    <h:panelGroup rendered="#{testBean.modeOne}">
      <ui:include src="modeOne.xhtml" />
    </h:panelGroup>
    <h:panelGroup rendered="#{testBean.modeTwo}">
      <ui:include src="modeTwo.xhtml" />
    </h:panelGroup>
  </h:form>
</h:body>
</html>

如您所见,此页面将根据 testBean bean 中的值有条件地包含 modeOne 页面或 modeTwo 页面.然后你有modeOne(默认):

As you can see this page will conditionally include either the modeOne page or the modeTwo page based upon the value in the testBean bean. Then you have modeOne (the default):

<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">
<ui:composition>
  <span>Okay, I&apos;m ready.  Take me to </span>
  <h:commandLink action="#{testBean.setModeTwo}">mode two.</h:commandLink>
</ui:composition>
</html>

在我的现实世界应用程序中,它是一个设置 modeTwo 所需内容的页面.设置完成后,此页面上的操作将引导您进入 modeTwo:

Which in my real world app would be a page that sets up things needed by modeTwo. Once set up, an action on this page will direct you to modeTwo:

<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">
  <ui:composition>
    <div>Here is your list:</div>
    <ui:repeat value="#{testBeanToo.list}" var="item">
      <div>#{item}</div>
    </ui:repeat>
  </ui:composition>
</html>

modeTwo 页面基本上在 ui:repeat 中显示 modeOne 页面的详细信息,因为实际信息位于集合中.主要托管bean(TestBean):

The modeTwo page basically presents a details for the modeOne page in a ui:repeat as the actual information is in a collection. The main managed bean (TestBean):

package test.lucastheisen.beans;


import java.io.Serializable;


import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;


@ManagedBean
@ViewScoped
public class TestBean implements Serializable {
    private static final long serialVersionUID = 6542086191355916513L;
    private Mode mode;
    @ManagedProperty( value="#{testBeanToo}" )
    private TestBeanToo testBeanToo;

    public TestBean() {
        System.out.println( "constructing TestBean" );
        setModeOne();
    }

    public String getTitle() {
        System.out.println( "	tb.getTitle()" );
        return mode.getTitle();
    }

    public boolean isModeOne() {
        return mode == Mode.One;
    }

    public boolean isModeTwo() {
        return mode == Mode.Two;
    }

    public void setModeOne() {
        this.mode = Mode.One;
    }

    public void setModeTwo() {
        testBeanToo.getReadyCauseHereICome();
        this.mode = Mode.Two;
    }

    public void setTestBeanToo( TestBeanToo testBeanToo ) {
        this.testBeanToo = testBeanToo;
    }

    private enum Mode {
        One("Mode One"),
        Two("Mode Two");

        private String title;

        private Mode( String title ) {
            this.title = title;
        }

        public String getTitle() {
            return title;
        }
    }
}

是所有主要数据的bean,TestBeanToo bean是细节:

Is the bean for all the main data, and the TestBeanToo bean would be for the details:

package test.lucastheisen.beans;


import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;


import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;


@ManagedBean
@ViewScoped
public class TestBeanToo implements Serializable {
    private static final long serialVersionUID = 6542086191355916513L;
    private ObjectWithList objectWithList = null;

    public TestBeanToo() {
        System.out.println( "constructing TestBeanToo" );
    }

    public String getTitle() {
        System.out.println( "	tb2.getTitle()" );
        return "Test Too";
    }

    public List<String> getList() {
        System.out.println( "	tb2.getList()" );
        return objectWithList.getList();
    }

    public void getReadyCauseHereICome() {
        System.out.println( "	tb2.getList()" );
        objectWithList = new ObjectWithList();
    }

    public class ObjectWithList {
        private List<String> list;

        public ObjectWithList() {
            list = new ArrayList<String>();
            list.add( "List item 1" );
            list.add( "List item 2" );
        }

        public List<String> getList() {
            return list;
        }
    }
}

推荐答案

<ui:repeat> 不检查自身的 rendered 属性(其实没有) 及其父视图何时被渲染.考虑使用 Tomahawk's <t:dataList> 代替.

<ui:repeat> does not check the rendered attribute of itself (it has actually none) and its parents when the view is to be rendered. Consider using Tomahawk's <t:dataList> instead.

这篇关于JSF ui:repeat 被 ui:include 包裹在 h:panelGroup 中,带有条件渲染...满嘴的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆