[jsr-314-open] Ajax rendering of components among compositions?

Alexandr Smirnov asmirnov at EXADEL.COM
Tue May 26 17:41:14 EDT 2009


JSF already has a smart enough code that look components by 'id'. Both
<h:outputLabel> and <h:message > use it to lookup target component that
is defined by the 'for' attribute, RichFaces library uses the same
strategy and it works very well. It would be better to use a same code
for <f:ajax> tag instead of simple local/global search.

Jim Driscoll wrote:
> I read this and thought "darn it, I *remember* that discussion, now that
> he brings it up".   And then, apparently, completely forgot that we
> added this functionality.  My apologies.
> 
> The switchlist example predates the naming change, going back to the
> dark days when we were just doing simple substitution into the JS function.
> 
> Other comments inline.
> 
> On 5/25/09 3:43 PM, Andy Schwartz wrote:
> 
> <snip>
> 
>>
>> This will result in the search expression "form1:switchlist:list1" being
>> resolved relative to the nearest naming container, which in this case is
>> the switchlist composite component itself. Since there is no
>> "form1:switchlist:list1" component within the composite component naming
>> container, findComponent() would return null, and the <f:ajax> tag
>> should log a warning.
> 
> Since that resolving code is only called by different function that
> immediately fails if it doesn't find the id, a warning seems
> unnecessary.  An expanded error message was used instead.
> 
>> However, instead of failing/logging a warning, we've got some code in
>> AjaxBehaviorRenderer.findComponent() that does the following:
>>
>>> UIComponent resolvedComponent = component.findComponent(expr);
>>> if (resolvedComponent == null) {
>>> // not found using a relative search, try an absolute search
>>> resolvedComponent = component.findComponent(':' + expr);
>>> }
>>
>> The bonus absolute search is not part of the spec - ie. is not typical
>> findComponent() id resolution behavior. This code should be removed and
>> replaced by a warning. (We should be able to make the warning clearer by
>> identifying the naming container that provided the scope of the search.
> 
> Logged as bug 1134
> 
> Fix checked in.
> 
>> In any case, when switching over to:
>>
>>> <f:ajax execute="@this list1" render="list1 list2"/>
>>
>>
>> Everything works as expected. We definitely should update this demo to
>> use this simpler, more spec-compliant solution.
> 
> Done.  Much cleaner.
> 
>> In order to try to reproduce the problem that David was seeing, I
>> decided to see whether I could update the "reload" button on the main
>> page from within the composite component. So, first I gave the reload
>> button an id:
>>
>>> <h:commandButton value="reload" type="submit" id="reload"/>
>>
>>
>> And then I added a new render target inside of our <f:ajax> tag (inside
>> of the composite component):
>>
>>> <f:ajax execute="@this list1" render="list1 list2
>>> :#{cc.parent.clientId}:reload"/>
>>
>>
>> Note that I used the leading ":" character to indicate that this is an
>> absolute id.
>>
>> I was thinking that "#{cc.parent}" would resolve to the composite
>> component's immediate parent, which in this case happens to be the
>> "form1" component. As such, I figured that "#{cc.parent.clientId}" would
>> give me "form1", and ":#{cc.parent.clientId}:reload" would produce the
>> absolute id ":form1:reload", which should target the outer reload button
>> (leaving aside the question of whether this is a good thing to do or
>> not).
>>
>> However, when I ran the test case, I hit the following error:
>>
>>> <f:ajax> contains an unknown id '::reload'
>>
>>
>> Okay, that's weird. So this means that "#{cc.parent.clientId}" is not
>> resolving to the parent component's client id, but instead to null/empty
>> string. Huh.
>>
>> After poking around some more, I found my way to the
>> com.sun.faces.el.CompositeComponentAttributesELResolver, which provides
>> some special handling for certain properties on the "cc" object,
>> including the "parent" property:
>>
>>> if (COMPOSITE_COMPONENT_PARENT_NAME.equals(propertyName)) {
>>> UIComponent c = (UIComponent) base;
>>> context.setPropertyResolved(true);
>>> UIComponent ccParent = UIComponent.getCompositeComponentParent(c);
>>> return ccParent;
>>> }
>>
>>
>> And, of course, UIComponent.getCompositeComponentParent() does not
>> return the composite component's parent, but instead returns the nearest
>> ancestor composite component. Which, in this particular demo, is...
>> null. Yuck. Okay, in retrospect, rather than re-defining the meaning of
>> "parent" here, we should have introduced a new derived property, eg.
>> "compositeParent", or something along those lines. (Unfortunately the
>> current behavior is defined by the spec - section 5.6.2.2, so too late
>> to do anything about this for 2.0.)
> 
> After thinking over this for a while, a lack of a real "parent" object
> may not be a bad thing.
> 
> After all, we'll want to tell people not to make components that
> invisibly modify the using page.  If you want to modify the using page,
> you should have to explicitly make the user say so, and mark the id's to
> be changed, or else you're going to make stuff that's impossible to
> maintain.
> 
> <snip>
> 
> Jim




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