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