Gang -
I have been spending a lot of time thinking about this topic and reading
the doc/looking at the source code. I can now say that I definitely
understand the difference between composite:insertFacet and
composite:renderFacet. :-) However, I am still confused about why we
decided to go with two separate tags and wanted to share my thoughts.
FWIW, I realize that it is like a year late to be bringing this up, but
thought it was important to discuss even if our options are limited at
this point.
Let's start by taking a look at composite:insertFacet:
<composite:implementation>
<h:panelGrid>
<composite:insertFacet name="caption"/>
</h:panelGrid>
</composite:implementation>
In the above case, the component specified for the "caption" facet ends
up in the facet map of the h:panelGrid component. This has certain
implications - eg. the component's parent property will point to the
h:panelGrid instead of the composite component. If we happen to insert
the facet into a NamingContainer, the client id will reflect this.
Currently we provide no way to insert a composite component's facet into
one of the composite's implementation components as a plain old
(non-facet) child. So, if instead of inserting the "caption" facet as a
facet on an h:panelGrid, I wanted to insert it as a (non-facet) child of
an h:panelGroup, eg:
<composite:implementation>
<h:panelGroup>
<!-- Insert the facet as a direct child here -->
</h:panelGroup>
</composite:implementation>
I cannot do that. Or, at least, I cannot do that with the same
semantics as <composite:insertFacet>, where the component specified via
the facet ends up as a child of the containing component (the h:panelGroup).
I can, however, use composite:renderFacet:
<composite:implementation>
<h:panelGroup>
<composite:renderFacet name="caption"/>
</h:panelGroup>
</composite:implementation>
This will cause the facet to be rendered as a child of the h:panelGroup,
but without being a child of the h:panelGroup.
This raises a number of questions. Why do we re-parent the facet
component when we want the component to be used by the parent component
as a facet, but not when we want the component to be used by the parent
as a direct child? Is there a reason why we need to treat the direct
child case differently (not re-parent) than the facet case (re-parent)?
Is there some benefit to having subtly different behavior between these
two cases?
My feeling is that the good old Facelets ui:insert tag got this right.
Facelets uses a single tag to handle insertion of ui:define'd components
into the template, regardless of whether the components are being
inserted as facets or directly children. So, for example, assuming I've
got a template that allows insertion of a "foo" component, I can do
either this:
<h:panelGrid>
<f:facet name="caption">
<!-- Insert the "foo" component into the "caption" facet
-->
<ui:insert name="foo"/>
</f:facet>
</h:panelGrid>
Or this:
<h:panelGroup>
<!-- Insert the "foo" component as a non-facet child -->
<ui:insert name="foo"/>
</h:panelGroup>
While the first case inserts the component as a facet and the second as
a direct child, both have the same semantics - ie. in both cases the
component that is being inserted ends up as a child of the parent
component that the child is being inserted into.
Actually, Facelets provides an API that is specifically designed to
handle this type of insertion: TemplateClient. The TemplateClient API
allows for clean/efficient insertion of included content into
templates. I believe that ui:define/ui:insert use this to insert
included content directly into the target location, avoiding the need to
re-locate the included components from one parent to another. This has
benefits when re-applying tags over a restored component tree, since
there is no need to repeatedly re-create (or re-locate) these components.
After thinking this through, one other question that I am left with is:
Is there a reason why we did not follow the ui:insert approach?
Yes, I realize that this is a moot point now, and no reason to dwell on
this, but I am still curious as to whether there were
limitations/problems with the ui:insert mechanism that prevented us from
following this precedent.
If we had the ability to revisit the design now, my preferred solution
would be to:
1. Deprecate/remove composite:renderFacet.
2. Re-spec composite:insertFacet to match the behavior of ui:insert.
I prefer this approach because I feel that we should share a single
insertion behavior across all of these use cases. The fact that we have
3 subtly different mechanisms is, well... bad. I also think that the
ui:insert approach has already been proven, which is in part why I favor
that approach.
Of course, I don't imagine that we have the ability to make this change
given that the JSF 2.0 spec has been final for some time now, and this
would be a significant change.
I suppose my second choice would be to deprecate both
composite:renderFacet/composite:insertFacet in JSF 2.1 and replace both
of these with a new composite:insert tag that matches ui:insert behavior.
Getting back to our original problem of not having control over the
"target" facet name:
If the spec does not yet provide a solution for this, I think that we
could/should solve this in one of two ways:
1. Add an attribute to composite:insertFacet that allows a target
facet name to be specified:
<h:panelGrid>
<composite:insertFacet name="backupCaption"
targetName="caption"/>
</h:panelGrid>
2. Specify that the target facet name can be picked up from a wrapping
<f:facet> tag:
<h:panelGrid>
<f:facet name="caption">
<composite:insertFacet name="backupCaption"/>
</f:facet>
</h:panelGrid>
I still prefer #1 as this is closer to ui:insert behavior, but given
that I have more fundamental reservations about
composite:insertFacet/composite:renderFacet, I don't feel especially
strongly about forcing #1 if people prefer #2.
Andy
Ken Paulsen wrote:
When / where should this discussion take place? Do we want to have a
call for this?
In addition to this issue, Alexander raised the issue that
f:insertFacet and f:renderFacet are confusing. Not sure if there's
anything we can do resolve this at this point, but minimally, it would
be worth ensuring the EG members understand the difference (which IMO,
is huge). In hindsight, f:insertFacet probably should have been
f:attachFacet, and of course had an optional "target" attribute for
Andy's case.
Ken
Andy Schwartz wrote:
> Thanks Ed -
>
> Ed Burns wrote:
>>
>> I happen to prefer #1, but everyone else favors #2, we'll go with #2.
>>
>
> Seems like some people prefer #2 as well, so perhaps this needs more
> discussion.
>
>> Andy, can you please file a spec issue and share the number with the
>> group? Once you have it, I'll add an entry in the changelog wiki.
>>
>>
>
> Sorry for taking so long to follow up on this. I have logged the
> following spec issue:
>
>
https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=631
>
>
> Andy
>
>