<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Gang -<br>
<br>
I spent the last couple of hours testing out various composite
component/f:ajax/id-related use cases, using the ajax-switchlist demo
(switchlistAjaxComponent.xhtml) as my base test case.&nbsp; The
ajax-switchlist component hierarchy looks like this (simplified down to
significant parts):<br>
<br>
<blockquote type="cite">&lt;h:body&gt;<br>
&nbsp; &lt;h:form id="form1"&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;ez:switchlist id="switchlist"/&gt;<br>
&nbsp;&nbsp;&nbsp; &lt;h:commandButton value="reload" type="submit"/&gt;<br>
&nbsp; &lt;/h:form&gt;<br>
&lt;/h:body&gt;</blockquote>
<br>
<br>
And &lt;ez:switchlist&gt; composite component contains the following
(again, stripped down to interesting parts):<br>
<br>
<blockquote type="cite">&nbsp; &lt;cc:implementation&gt;<br>
  <br>
&nbsp;&nbsp;&nbsp; &lt;h:selectManyListbox id="list1"/&gt;<br>
  <br>
&nbsp;&nbsp;&nbsp; &lt;h:commandButton id="move1to2"&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;f:ajax execute="@this #{cc.clientId}:list1"
render="#{cc.clientId}:list1 #{cc.clientId}:list2"/&gt;<br>
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/h:commandButton&gt;<br>
  <br>
&nbsp;&nbsp;&nbsp; &lt;h:selectManyListbox id="list2"/&gt;<br>
  <br>
&nbsp; &lt;/cc:implementation&gt;</blockquote>
<br>
<br>
First thing to note...&nbsp; The execute/render ids are specified in an
overcomplicated manner.&nbsp; As I mentioned in email earlier today, the
f:ajax execute/render ids are spec'ed to adhere to findComponent() id
resolution semantics.&nbsp; Since the &lt;f:ajax&gt; behavior is attached to
a component that is in the same naming container as selectManyListbox
components that we are targeting, we can simplify from this:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;f:ajax execute="@this
#{cc.clientId}:list1" render="#{cc.clientId}:list1
#{cc.clientId}:list2"/&gt;</blockquote>
<br>
<br>
To:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;f:ajax execute="@this list1"
render="list1 list2"/&gt;</blockquote>
<br>
<br>
Ah, that feels much better.&nbsp; Actually, this isn't just a
simplification... this is correct solution.&nbsp; Unfortunately the original
code only happens to work due to non-spec compliant implementation
behavior.&nbsp; That is, when we specify:<br>
<br>
<blockquote type="cite">&nbsp; render="#{cc.clientId}:list1"</blockquote>
<br>
<br>
This is the same as specifying:<br>
<br>
<blockquote type="cite">&nbsp; render="form1:switchlist:list1"</blockquote>
<br>
<br>
Which should have the same behavior as calling:<br>
<br>
<blockquote type="cite">&nbsp;
move1to2ButtonComponent.findComponent("form1:switchlist:list1");</blockquote>
<br>
<br>
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.&nbsp; Since there is no
"form1:switchlist:list1" component within the composite component
naming container, findComponent() would return null, and the
&lt;f:ajax&gt; tag should log a warning.<br>
<br>
However, instead of failing/logging a warning, we've got some code in
AjaxBehaviorRenderer.findComponent() that does the following:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UIComponent resolvedComponent =
component.findComponent(expr);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (resolvedComponent == null) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // not found using a relative search, try an absolute search<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; resolvedComponent = component.findComponent(':' + expr);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
</blockquote>
<br>
The bonus absolute search is not part of the spec - ie. is not typical
findComponent() id resolution behavior.&nbsp; This code should be removed
and replaced by a warning.&nbsp; (We should be able to make the warning
clearer by identifying the naming container that provided the scope of
the search.<br>
<br>
In any case, when switching over to:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;f:ajax execute="@this list1"
render="list1 list2"/&gt;</blockquote>
<br>
<br>
Everything works as expected.&nbsp; We definitely should update this demo to
use this simpler, more spec-compliant solution.<br>
<br>
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.&nbsp; So, first I gave the reload
button an id:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp; &lt;h:commandButton value="reload"
type="submit" id="reload"/&gt;</blockquote>
<br>
<br>
And then I added a new render target inside of our &lt;f:ajax&gt; tag
(inside of the composite component):<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;f:ajax execute="@this list1"
render="list1 list2 :#{cc.parent.clientId}:reload"/&gt;</blockquote>
<br>
<br>
Note that I used the leading ":" character to indicate that this is an
absolute id.<br>
<br>
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.&nbsp; 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).<br>
<br>
However, when I ran the test case, I hit the following error:<br>
<br>
<blockquote type="cite">&lt;f:ajax&gt; contains an unknown id '::reload'</blockquote>
<br>
<br>
Okay, that's weird.&nbsp; So this means that "#{cc.parent.clientId}" is not
resolving to the parent component's client id, but instead to
null/empty string.&nbsp; Huh.<br>
<br>
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:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if
(COMPOSITE_COMPONENT_PARENT_NAME.equals(propertyName)) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UIComponent c = (UIComponent) base;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context.setPropertyResolved(true);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UIComponent ccParent =
UIComponent.getCompositeComponentParent(c);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ccParent;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</blockquote>
<br>
<br>
And, of course, UIComponent.getCompositeComponentParent() does not
return the composite component's parent, but instead returns the
nearest ancestor composite component.&nbsp; Which, in this particular demo,
is... null.&nbsp; Yuck.&nbsp; 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.&nbsp;
(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.)<br>
<br>
I thought I might be able to work around this by avoiding the reference
to the "cc" implicit object - ie. thought I might be able to get this
to work by using the "component" implicit object instead of the "cc"
object, eg: ":#{component.parent.parent.clientId}:reload".&nbsp; But I ended
up running into the same problem.<br>
<br>
So, David - it is possible that you are running into this as well.&nbsp;
It's kind of tough to tell with the auto-generated ids in your
content.&nbsp; Any chance you could add explicit ids to the naming
containers in your sample just to make it easier to understand the
client ids that are being rendered?<br>
<br>
On a positive note, I was able to manually pass in the reload button id
to the composite component without any problems.&nbsp; To do this, I added
the following to the composite:interface:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp; &lt;cc:attribute name="reloadId"/&gt;</blockquote>
<br>
<br>
And the following to the composite:implementation:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;f:ajax execute="@this list1"
render="list1 list2 #{cc.attrs.reloadId}"/&gt;</blockquote>
<br>
<br>
And then updated the main page to specify the new attribute:<br>
<br>
<blockquote type="cite">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ez:switchlist id="switchlist"
reloadId=":form1:reload"/&gt;</blockquote>
<br>
<br>
This worked without any problems.<br>
<br>
David - since I think we all agree that this is the preferred approach,
and since there doesn't seem to be any way to get at a composite
component's actual parent (unless I am missing something), this seems
like the right way to go for your J1 demo.&nbsp; If you continue to have
problems with this approach, maybe cc me when you send Ryan your war.&nbsp;
Don't know how much time I'll have to take a look, but I am definitely
curious. <br>
<br>
Andy<br>
<br>
<br>
David Geary wrote On 5/25/2009 1:36 PM ET:
<blockquote
 cite="mid:75fa9e650905251036nfc2c22bj7ad177dcdc5224af@mail.gmail.com"
 type="cite">
  <meta http-equiv="Context-Type"
 content="text/html; charset=ISO-8859-1">
2009/5/24 Jim Driscoll <span>&lt;<a moz-do-not-send="true"
 href="mailto:Jim.Driscoll@sun.com">Jim.Driscoll@sun.com</a>&gt;</span><br>
  <div>
  <blockquote>
    <div>On 5/24/09 8:39 PM, David Geary wrote:<br>
    <blockquote>
And that id is *exactly* what &lt;f:ajax&gt; says it cannot find. It's
in the<br>
page, but &lt;f:ajax&gt; cannot find it?!?<br>
      <br>
My guess is that &lt;f:ajax&gt; is evaluating the id before the page is<br>
completely constructed, and therefore, it doesn't find it, but that's<br>
just a WAG on my part.<br>
      <br>
So, if this is not correct:<br>
      <br>
&lt;f:ajax render="#{cc.parent.clientId}:image"/&gt;<br>
      <br>
Then how do I access the image in the parent (map) component?<br>
      <br>
It seems to me that I'm using &lt;f:ajax&gt; correctly, but I'd be
happy to be<br>
told otherwise.<br>
    </blockquote>
    <br>
    <br>
    </div>
It's late, but yes, that looks correct, and yes, your guess sounds
correct. &nbsp;Could you file this as an impl bug?</blockquote>
  <div><br>
Okay. I'll send a WAR to Ryan, and see if we can get this fixed asap.
I'd like to get this working for my J1 demo.<br>
  </div>
  <blockquote><br>
    <br>
Now, we do need to fix that as a bug, but I must argue that your use
case represents bad practice. &nbsp;Your component is using ajax inside a
component to modify the using page. &nbsp;That's difficult to maintain, and
I suspect it will lead to obfuscated code quite easily. &nbsp;I'd instead
argue that if you are going to have one component modify another, you
should either group them into one composite, or, have the ID of the
component you act upon passed in as an attribute (say "for="?)</blockquote>
  <div><br>
Yup, I concur--too much coupling between parent and child components.
Unfortunately, I can't seem to pass the component ID to the child
component either. IOW, this doesn't work:<br>
  <br>
In parent component:<br>
  <br>
&nbsp; &lt;places:mapZoomControl
componentToRender="#{cc.clientId}:image"/&gt;<br>
  <br>
And in mapZoomControl.xhtml:<br>
  <br>
&nbsp; &lt;composite:attribute name="componentToRender"/&gt;<br>
&nbsp; ...<br>
&nbsp; &lt;f:ajax render="#{cc.attrs.componentToRender}"/&gt;<br>
  <br>
I suppose it's not surprising that the preceeding doesn't work--it
looks like a manifestation of the same bug. I'll give Ryan a buzz.<br>
  <br>
Thanks,<br>
  <br>
  <br>
david<br>
  <br>
  </div>
  <blockquote><br>
    <br>
Of course, that second usage suggestion opens up another hole in the cc
api - the lack of ability to do name resolution. &nbsp;Though if/when we get
method parameters, then cc.findComponent will work, I guess. &nbsp; &nbsp;Though
I've been saying that for a pretty long time now, I should check on
when we're getting those method params...<br>
    <br>
Jim<br>
  </blockquote>
  </div>
  <br>
</blockquote>
<br>
</body>
</html>