Hi Simon,
 comments inside.

Simon Kitching napsal(a):
---- "Sochor Zdeněk" <[EMAIL PROTECTED]> schrieb:
Hi,
as to why does it work, the answer should be simple - almost all renderers in MyFaces do ALL encoding work in encodeEnd method (including rendering children).

To be more specific (he says, after some hurried study of the code):

Normally it is the role of the ViewHandler to call 
encodeBegin/encodeChildren/encodeEnd on all components. Because content in the 
template needs to be woven into output from JSF components, generating a view 
is not just walking the component tree.

However components where rendersChildren=true are different. In that case the child 
components all need to be built before encodeBegin is called on the 
"rendersChildren" component. So  (at least for JSF1.1+jsp) the ViewHandler just 
limits itself to building the components, *not* invoking their encode methods. The 
rendersChildren component is then responsible for invoking the children.

The Renderer implementation of encodeChildren below does indeed seem buggy to 
me; it correctly handles one level of children but fails if a component that 
sets rendersChildren=true has grandchildren.

However in practice I think every component that implements encodeChildren 
always overrides this buggy default and invokes something like 
RenderUtils.renderChildren to do it properly. There aren't very many of them.

As Sochor mentioned, many of them do this in the renderer encodeEnd, although 
some do it in encodeChildren.

But what do i wonder more is why page's component tree contains ALL previously rendered/encoded components.
Wouldn't it make sense to remove non-rendered components from it?
I came across this issue when discussing topic: "TabbedPane does not validate non-selected tabs in server side tab switching mode (Relaed to TOMAHAWK-1012 <https://issues.apache.org/jira/browse/TOMAHAWK-1012>)."

Best regards,
  Zdenek


Non-rendered components can still have state configured into them by java code. Setters can be called on those components to set properties, and each component has an arbitrary Attributes map that can hold data. Discarding the non-rendered component would discard that data.
Doesn't this approach lead to two iteration of component tree?
1.
on the first access to page create the whole tree regardless of rendered attribute (so that all componentss could be interacted with) and encoding them to view
   A little note - i can't find checks
       if (!isRendered()) return;
found in many methods of UIComponentBase class from MyFaces in respective RI class. on all subsequent acesses to page call decode on the whole tree (to refresh all potential changes both from page input AND code)

2. render only components with rendered attribute=true


I think another reason is that when re-rendering a page it is quite tricky to match up component 
declarations in the "template" file with existing components in the tree. When every 
component in the template file has an explicit id there is no trouble, but that is not usually the 
case. The only solution when a tag in the template file is found without an id is to assume it 
corresponds to the next anonymous component in the existing view tree. This "guessing" 
approach doesn't work well if components get removed from the tree just because they are not 
rendered. But the thought of absolutely requiring an id on every h:outputText and h:outputLabel in 
the template file is not tempting.

This wouldn't be an issue if whole tree was encoded (it would have always same structure).

I cannot think of any other reasons, but these seem enough to me.


Regards,

Simon

--
A. Because it breaks the logical sequence of discussion
Q. Why is "top posting" bad?



============


Mario Ivankovits napsal(a):
Hi!

In JSF 1.1 I am curious about the javax.faces.renderer.Renderer class in
JSF 1.1, in particular the following piece of code:

    public void encodeChildren(FacesContext context,
                               UIComponent component)
            throws IOException
    {
        if (context == null) throw new NullPointerException("context");
        if (component == null) throw new NullPointerException("component");
List children = component.getChildren();
        for (int i=0; i<children.size(); i++)
        {
            UIComponent child = (UIComponent) children.get(i);
if (!child.isRendered())
            {
                continue;
            }

            child.encodeBegin(context);
            if (child.getRendersChildren())
            {
                child.encodeChildren(context);
            }
            child.encodeEnd(context);
        }
    }


I wonder WHEN are the children rendered if the component returns false
on getRendersChildren here.
And how/why does it work when mixing things, lets say you have
t:div/h:panelGroup/t:div
where t:div returns false on getRendersChildren() and h:panelGroup
returns true.

Is there a simple answer to this?

Ciao,
Mario


Best regards,
 Zdenek

Reply via email to