jsr372-experts@javaserverfaces-spec-public.java.net

[jsr372-experts] Re: recursive use of a custom component

From: Michael Müller <michael.mueller_at_mueller-bruehl.de>
Date: Tue, 9 Feb 2016 06:37:55 +0100

Hi Bauke,

Thanks for this information.

And for reminding the name. Because composite components are a kind of
simplified custom components, I use the wrong name half the time.
Hopefully I'll learn some day...
(I kept the rendered attribute because I switched back and forward to
ui:repeat)

Herzliche Grüße - Best Regards,

Michael Müller
Brühl, Germany
blog.mueller-bruehl.de <http://blog.mueller-bruehl.de/>
it-rezension.de <http://it-rezension.de/>
@muellermi


Read my books
"Web Development with Java and JSF": https://leanpub.com/jsf
"Java Lambdas und (parallel) Streams" Deutsche Ausgabe:
https://leanpub.com/lambdas-de
"Java Lambdas and (parallel) Streams" English edition:
https://leanpub.com/lambdas

Am 08.02.2016 um 22:02 schrieb Bauke Scholtz:
> Hi,
>
> Technical problem is the context of #{cc} and statefulness of #{cc.attrs}.
>
> The #{cc} refers to *current* composite. So when you pass #{cc} to the
> nested composite , it will in turn refer the nested composite itself, not
> its parent. This results in infinite loop. This can be tricked by passing
> #{cc.parent} to the nested composite instead.
>
> The statefulness of #{cc.attrs} can be tricked by overriding
> setValueExpression() and delegating to a local variable instead of
> statehelper and then referring the local variable via #{cc.node} instead of
> the attribute. This will avoid another infinite loop when nested component
> refers attributes of its parent.
>
> Here's an example:
>
> <cc:interface componentType="treeComposite">
> <cc:attribute name="node" type="org.omnifaces.model.tree.TreeModel" />
> </cc:interface>
> <cc:implementation>
> <c:if test="#{not empty cc.node.children}">
> <ul>
> <c:forEach items="#{cc.node.children}" var="node" varStatus="loop">
> <li>#{node.data} <my:tree node="#{cc.parent.node.children[loop.index]}"
> /></li>
> </c:forEach>
> </ul>
> </c:if>
> </cc:implementation>
>
> With this backing component:
>
> @FacesComponent("treeComposite")
> public class TreeComposite extends UINamingContainer {
>
> private TreeModel node;
>
> @Override
> public void setValueExpression(String name, ValueExpression binding) {
> if ("node".equals(name)) {
> setNode((TreeModel)
> binding.getValue(getFacesContext().getELContext()));
> }
> else {
> super.setValueExpression(name, binding);
> }
> }
>
> public TreeModel getNode() {
> return node;
> }
>
> public void setNode(TreeModel node) {
> this.node = node;
> }
>
> }
>
>
> By the way, just a few remarks: this is a composite component, not a custom
> component. The <cc:attribute class> doesn't exist, you meant to use
> <cc:attribute type>. The <c:forEach> doesn't support rendered attribute.
> Just omit it.
>
> Cheers, B
>
>