[jsr-314-open] composite:insertFacet target facet name

Ken Paulsen Ken.Paulsen at Sun.COM
Thu Sep 24 20:33:34 EDT 2009



Andy Schwartz wrote:
> 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,
There is no way to add a facet without it being re-parented.  Perhaps we 
should have changed the behavior to allow non-child components to be 
facets of a component.
> but not when we want the component to be used by the parent as a 
> direct child?
As you pointed out, there is no way to add a component from the page to 
a component in the EZComp as a child (only as a facet).  If it were 
possible, under the current JSF code, it too would be re-parented.
>   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?
Yes, the not-reparent case is not a child.  It is an omission and were 
it to be added,it too would re-parent (unless we changed the rules).

The reason the 2 tags are treated differently is this:  1 modifies the 
component tree; the other occurs during rendering.  Two very different 
phases in JSF.

If we were to explore not re-parenting, we'd probably need to create a 
ProxyComponent which could be added to the child and delegate everything 
to the real component which would remain on the parent.  That might work 
nicely.
>
> 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.
Which is wrong.  The parent ideally should be the *composite 
component*.  Keep in mind the template is a black box that the page 
author should not know anything about.  So if I do:

    <my:ezComponent id="foo">
       <f:facet name="myfacet">
             <h:outputText id="usercomp" value="here" />
       </f:facet>
    </my:ezComponent>

So looking at this page excerpt, you'd say the parent of "usercomp" is 
"foo".  And if foo is a naming container, the clientId would be 
something like: "...:foo:usercomp".

However, if the implementation of the ezcomp component (that the page 
author has no control over and no know knowledge of) is implemented like 
this:

    ...
    <some:namingcontainer id="hiddenContainer">
       <ui:insert facet="myfacet" />
    </some:namingcontainer>
    ...

Then we have problems:

1)  The parent is *not* "foo" as the page author expected (and as would 
be the case with ALL Java-based components).

2) The clienId is not what we expected: 
"...:foo:...:hiddenContainer:myfacet"

3) Changes that a component author makes to the component will break any 
code the page author writes that depends on the location or clientId of 
the facet component.

Now... was facelets wrong w/ ui:insert?  Absolutely not...  In facelets 
they were not making components, they were making pages.  The page 
author had visibility and full control of the UIComponent tree structure 
that was being created.  VERY different than the component scenario.  
Which is likely why facelets was never able to create real components.

> 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.
Not sure I follow you.  But I "think" you're describing meta-data that 
represents the "files" which define the UIComponent tree (aka, VAST).  
Which is something I have been advocating for and can greatly help.  
However, once components are instantiated as UIComponents, they do 
either have to be relocated, copied, or proxied (never seen this done in 
practice)... so I think there's more to it than what you suggest.

> 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?
See above.
>
> 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 think we could do this if we can also ensure that components are NOT 
re-parented.  Then we could provide the correct behavior AND provide a 
nice syntax for component authors.  However, I don't envy the person 
(Ryan) that has to implement this. :)  There are a lot of tags and code 
that would have to have special-case stuff to make this happen.

Ken
> 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
>>>
>>>
>




More information about the jsr-314-open-mirror mailing list