Jsf 如何阻止递归复合组件递归地包含自身
有没有可能让一个JSF组件具有ui:repeat,并且在repeat调用中包含相同的组件?这是因为我正在构建问题之树:Jsf 如何阻止递归复合组件递归地包含自身,jsf,jsf-2,recursion,facelets,composite-component,Jsf,Jsf 2,Recursion,Facelets,Composite Component,有没有可能让一个JSF组件具有ui:repeat,并且在repeat调用中包含相同的组件?这是因为我正在构建问题之树: <cc:interface> <cc:attribute name="questions" required="true" /> <cc:attribute name="renderQuestions" required="true" default="true" /> </cc:interface> <c
<cc:interface>
<cc:attribute name="questions" required="true" />
<cc:attribute name="renderQuestions" required="true" default="true" />
</cc:interface>
<cc:implementation>
<c:if test="#{cc.attrs.renderQuestions}">
<ui:repeat value="#{cc.attrs.questions}" var="q">
<p:panelGrid columns="2">
<h:outputLabel value="#{q.question}"></h:outputLabel>
<p:selectBooleanButton onLabel="#{messages['commons.yes']}"
offLabel="#{messages['commons.no']}" onIcon="ui-icon-check"
offIcon="ui-icon-close" value="#{q.ok}">
<p:ajax update="@all"></p:ajax>
</p:selectBooleanButton>
</p:panelGrid>
<cf:question renderQuestions="#{q.ok}" questions="#{q.children}" />
</ui:repeat>
</c:if>
</cc:implementation>
当前我有stackoverflow?使用视图生成时间标记来停止递归,而不是使用视图渲染时间标记。组件树是在视图生成期间生成的。
rendered
属性不会在视图生成时计算,而是在视图渲染时计算。所以你的构造基本上是把自己包含在一个无限循环中。您应该已经知道,stackoverflowerrror
是由递归引起的,递归太深,内存堆栈无法再处理它(通常约1000次迭代)
用
替换
,它将按预期工作。顺便说一句,renderQuestions
可以通过省略对子项的检查来简化。如果没有子对象,
无论如何都不会呈现任何内容
如果您碰巧在此构造中使用了视图范围bean,并且正在使用Mojarra实现,那么请确保至少升级到2.1.18,因为在旧版本中,将视图构建时间标记属性绑定到视图范围bean属性会破坏视图范围
另见:
- -解释“视图构建时间”与“视图渲染时间”
rendered
属性不会在视图生成时计算,而是在视图渲染时计算。所以你的构造基本上是把自己包含在一个无限循环中。您应该已经知道,stackoverflowerrror
是由递归引起的,递归太深,内存堆栈无法再处理它(通常约1000次迭代)
用
替换
,它将按预期工作。顺便说一句,renderQuestions
可以通过省略对子项的检查来简化。如果没有子对象,
无论如何都不会呈现任何内容
如果您碰巧在此构造中使用了视图范围bean,并且正在使用Mojarra实现,那么请确保至少升级到2.1.18,因为在旧版本中,将视图构建时间标记属性绑定到视图范围bean属性会破坏视图范围
另见:
- -解释“视图构建时间”与“视图渲染时间”
<composite:interface>
[..]
<composite:attribute name="level" required="true" default="0"/>
</composite:interface>
<composite:implementation>
<c:if test="#{cc.attrs.level == 0}">
<a4j:repeat value="#{cc.attrs.list}" var="subList" rendered="#{cc.attrs.list != null}">
<xx:recursiveComponent list="#{subList}" id="subComponent" level="1"/>
</a4j:repeat>
</c:if>
</composite:implementation>
[..]
在构建时使用level属性以避免无休止的递归,a4j:repeat(在您的情况下是ui:repeat)的renered属性将在渲染时进行评估。基于BalusC的答案,我创建了一个类似这样的解决方案
<composite:interface>
[..]
<composite:attribute name="level" required="true" default="0"/>
</composite:interface>
<composite:implementation>
<c:if test="#{cc.attrs.level == 0}">
<a4j:repeat value="#{cc.attrs.list}" var="subList" rendered="#{cc.attrs.list != null}">
<xx:recursiveComponent list="#{subList}" id="subComponent" level="1"/>
</a4j:repeat>
</c:if>
</composite:implementation>
[..]
level属性在构建时使用,以避免无休止的递归,a4j:repeat(或者在您的情况下是ui:repeat)的renered属性将在渲染时求值。理论上,嵌套两个
ui:repeat
标记没有问题。不过,这取决于您的cf:question
标记的内容。您好,cf:question的内容与上面的代码相同,它是呈现该视图的递归调用。我们的目标是编写问题及其子问题(如果有),然后,感谢您在视图端执行这种递归。为什么不在问题上构建一个双重迭代呢?不幸的是,我想要的是一个n层次的问题,这就是为什么双重迭代不起作用的原因。理论上,嵌套两个ui:repeat
标记没有问题。不过,这取决于您的cf:question
标记的内容。您好,cf:question的内容与上面的代码相同,它是呈现该视图的递归调用。我们的目标是编写问题及其子问题(如果有),然后,感谢您在视图端执行这种递归。为什么你不在问题上建立一个双重迭代呢?不幸的是,我想要的是一个n层次的问题,这就是为什么双重迭代不行的原因。嗨,巴卢斯,谢谢你的回答,但是在你上面指定的更改之后,我仍然有相同的错误。我正在更新上面的帖子。显然这个表达式从来没有计算过false
。看起来renderQuestions=“#{q.ok}”不起作用,但是打印q.ok会显示'false',所以它不应该渲染视图,但它似乎会导致堆栈溢出,很奇怪。嗨,Balus,谢谢你的回复,但是在你上面指定的更改之后,我仍然有相同的错误。我正在更新上面的帖子。很明显,这个表达式从来没有计算过false
。看起来renderQuestions=“#{q.ok}”不起作用,但是打印q.ok会显示“false”,所以它不应该渲染视图,但它似乎会导致堆栈溢出,这很奇怪。