You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by Andrew Robinson <an...@gmail.com> on 2008/01/30 23:14:01 UTC

Partial triggers and "::" naming -- take 2

Sorry that this email is long, but it is a sensitive issue, so please read
on.

https://issues.apache.org/jira/browse/TRINIDAD-757

was reported because the behavior of the code did not match the JavaDoc
description.

Thread: http://tinyurl.com/373smc

At that time, it was decided by others that changing the JavaDoc would be
easier that changing the code.

The question became -- should "foo" work like UIComponent.findComponent() or
should it look it the parent component.

I have had feedback from people using Trinidad, that the change is breaking
current code, so the argument for not breaking ppl. by changing the JavaDoc
has not panned out.

Take this example:
<f:subview id="A">
  <tr:group id="B">
    <tr:panelGroupLayout id="C">
      <tr:panelBox id="D">
        <tr:commandButton id="E" />
        <tr:table id="F" partialTriggers="#{pt}">
          <tr:column>
            <tr:commandButton id="G"/>...

Currently, if I want to F to trigger on G, I have to use #{pt} = "F:G". If I
want F to trigger on E, I have to use #{pt} = "E":

        <tr:table id="F" partialTriggers="E">
        <tr:table id="F" partialTriggers="F:G">

Not only is this confusing (well all solutions are a bit confusing
admittedly), but really bad for performance.

If #{pt} = "F:G", this is the code that happens (NC means NamingContainer.
"--" refers to the result):

comp = "F".getParent(); -- comp == "D"
check if comp is NC -- false

(repeat comp.getParent(), test for NC)
finds "A"

now call "A".findComponent("F:G")
UIComponent searches in this order to find "F":
A, B, C, D, E, F
(note that this code is broken if the JSF 1.2_04-p02 RI
UIComponentBase.findComponent() but is correct in MyFaces 1.1.5:
  https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=690)

Now it searches all the children of F to find G

This code has way too much overhead. I was already at "F", why do I have to
search for it?


What would be cleaner:
        <tr:table id="F" partialTriggers="::E">
        <tr:table id="F" partialTriggers="G">

In the current implementation "::E" and "E" are identical!

In the "cleaner" approach "::E" and "E" are only identical if the current
component is not an NC.

If you read the UIComponent docs:
http://tinyurl.com/2dfak5

You will see that for the code
  comp.findComponent("foo")
if comp is an NC, then it will check if comp is foo, or find the child that
is foo.

partialTriggers differs from this. That means that if a developer
understands the JSF method, they will not expect the partialTriggers
implementation.

What I (and a few of my co-workers) would prefer as the definition of
partialTriggers:

   - If the search expression begins with a single ':', the base will be
   the root UIComponent of the component tree. The leading separator character
   will be stripped off, and the remainder of the search expression will be
   treated as a "relative" search expression as described below.
   - Otherwise, if this UIComponent is a NamingContainer it will serve as
   the basis.
   - Otherwise, search up the parents of this component. If a
   NamingContainer is encountered, it will be the base.
   - Otherwise (if no NamingContainer is encountered) the root
   UIComponent will be the base.
   - If the search expression starts with multiple ':' characters:
      - For each ':' beyond the first, find the parent component that
      is a NamingContainer. Therefore ':::comp' will begin the
"relative" search
      from the NamingContainerthat is a ancestor of the
NamingContainer that comp
      is a child of.

The search expression (possibly modified in the previous step) is now a
"relative" search expression that will be used to locate the component (if
any) that has an id that matches, within the scope of the base component.
The match is performed as follows:

   - If the search expression is a simple identifier, this value is
   compared to the id property, and then recursively through the facets and
   children of the base UIComponent (except that if a descendant
   NamingContainer is found, its own facets and children are not searched).
   - If the search expression includes more than one identifier separated
   by ':', the first identifier is used to locate a NamingContainer by the
   rules in the previous bullet point. Then, the findComponent() method of this
   NamingContainer will be called, passing the remainder of the search
   expression.

This would improve performance, actually give a purpose to "::foo" and be in
sync with the method of searching for a component based on the JSF
specification.

Since we know current code is already broken, I do not feel that
"maintaining backward compatibility" is a valid reason to say no.

Thanks,
Andrew

PS - Wow, hard to believe you read all that, thanks! (or did you just scroll
to the end :-) )