jsr344-experts@javaserverfaces-spec-public.java.net

[jsr344-experts] Re: Referencing composite component attributes in child components outside of a tree traversal

From: Edward Burns <edward.burns_at_oracle.com>
Date: Fri, 17 Feb 2012 13:20:09 -0800

I tried to summarize the discussion on this but it boils down to an
impedence mismatch between EL and the JSF Java API.

>>>>> On Wed, 17 Aug 2011 20:17:36 -0400, Kito Mann <kito.mann_at_virtua.com> said:

KM> Section 5.6.2.1 (Implicit Object ELResolver for Facelets and Programmatic
KM> Access) of the spec states the following:

KM> cc -> the current composite component relative to
KM> the declaring page in which the expression appears.

KM> Since "current composite component" usually means the current composite
KM> being processed during a tree traversal, "cc" can return null when it's
KM> referenced elsewhere (i.e. in an action listener);.

KM> I'm thinking that the "cc" implicit variable should return the parent
KM> composite component in cases where no "current composite component" is
KM> available.

>>>>> On Fri, 19 Aug 2011 14:31:14 -0500, Leonardo Uribe <lu4242_at_gmail.com> said:

LU> I have been thinking about this and it seems the missing part has to
LU> be with UIComponent.findComponent(String expr).

LU> In theory, findComponent allow us to find a "real" component instance
LU> using a expression, but when the component is inside a datatable or
LU> other "iteration" component, the state is bound in some way with the
LU> generated clientId, which can only be found when the call is put in
LU> context, that means "we are in a valid row".

LU> But there is no method to get a findComponent expression based on a
LU> component instance (getFindComponentExpression), or a way to traverse
LU> the component tree just like with invokeOnComponent or visitTree, but
LU> passing a "find component expression" as param, instead the clientId.
LU> Maybe it is possible to create a custom VisitContext based on "find
LU> component expression", but I have not checked it yet.

The commonly used approach is to call invokeOnComponent() with passing
in an anonymous inner class that takes action on the found component.
In this way invokeOnComponent() operates as a context-aware
findComponent().

KM> Hmm.. Isn't the problem really that the ValueExpression
KM> implementations have no reference to the component for which they
KM> were created? If the expression knew which component it was created
KM> for, it could use that component to find the composite component
KM> parent (among other things).

B> Maybe I'm misunderstanding this, but how is this different than
B> accessing any other potentially-EL-bound attribute in JSF? EL-bound
B> values can only be safely evaluated when the component in question is in
B> the correct context. This means either:
B> a) During lifecycle processing
B> b) During a tree visit callback
B> c) During an invokeOnComponent callback (which is really just a
B> degenerate version of b)

B> I agree that this is has always been a major usability problem with JSF,
B> but that's how JSF is.

KM> The difference here is that the EL variable is "cc". The component is
KM> simply referring to one of its own properties, not a backing bean, so a
KM> developer would expect that to work when making an arbitrary call to the
KM> component.

KM> So, I suppose the question is really whether or not we should support the
KM> ability to use findComponent() and evaluate the properties outside of a
KM> tree traversal. I've found that calling UIComponent.pushComponentToEL()
KM> works in some cases if you call it before accessing the component's
KM> properties. Perhaps that's the solution -- just manually call that method
KM> first.

The specification for #{cc} has always been such that it's only useful
within the <cc:implementation> section. In that usage, it always refers
to the current composite component. In the case of nested composite
components this can get a little tricky, but it is still well defined.

I am seeing people suggest that we have some way to make #{cc} useful in
other contexts. I haven't seen a way to do that cleanly, so I'm going
to push back on it until I do.

Also on this thread was the sentiment that findOnComponent() doesn't
handle iterating components. I counter by stating that
invokeOnComponent() does exactly what we want in this case. If you want
to take action on a component that is within an iterating component,
pass an anonymous inner class to invokeOnComponent().

Summary: I can't see what action we can take to make this any easier
right now, but I'm open to suggestions.

Thanks,

Ed

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
| homepage:               | http://ridingthecrest.com/