javaserverfaces
  1. javaserverfaces
  2. JAVASERVERFACES-2588

clientbehavior rendered multiple times with nested composite components

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Works as designed
    • Affects Version/s: 2.1.14
    • Fix Version/s: 2.2.5
    • Component/s: None
    • Labels:
      None

      Description

      Hi,

      I'd like to have a couple of composite components: "toolbar" and "editor".

      The toolbar is used in several edit pages, but can also be nested within the editor component.

      I need ajax behavior on some pages, so I have the toolbar declare a clientbehavior like this:

      toolbar.xhtml: <cc:clientBehavior name="save" targets="toolbarSaveBtn" event="action" />

      When I use the toolbar directly in pages everything is fine, but if I attempt to nest the toolbar into the editor component and "bridge" the clientbehavior with:

      editor.xhtml: <cc:clientBehavior name="save" targets="toolbar" event="save" />

      (Where toolbar is the toolbar component id).

      The containing page has:

      <form>
      <editor:editor id="editor">
      <f:ajax event="save" listener="#

      {backingBean.saveNew}

      " execute="@form" render="@all"
      </editor:editor>
      </form>

      When the toolbar internals are "inlined/copied" directly into "editor" it behaves like expected, when I put the toolbar into the editor component I see my listener getting triggered multiple (4 i think) times per click on the toolbar button.

      When I do a view source in the browser it looks like the client behavior has been included twice in "onclick".

        Issue Links

          Activity

          Hide
          Manfred Riem added a comment -

          Can you please attach an example application (with sources) and no external dependencies that demonstrates the problem?

          Show
          Manfred Riem added a comment - Can you please attach an example application (with sources) and no external dependencies that demonstrates the problem?
          Hide
          chris_dezide added a comment -

          I've manged to create a minimalistic example (maven project) that illustrates what I'm seeing.

          You can run it with: "mvn jetty:run-war"

          Clicking the first save button / cancel link works (toolbar directly included in page). Clicking second save button results in the listener being triggered twice - the second cancel link does not do this, so I assume it is a h:commandButton "feature".

          I noticed that the nested component seemed to work properly if there was just one clientbehavior bound for the toolbar save button. In the actual code where I see the error, we have more than one client behavior bound - So I added a "Cancel" link with a clientbehavior to the sample project and then the Save button started resulting in double submits.

          I really hope this can get fixed as it makes it really hard to create building blocks for more complex pages.

          Show
          chris_dezide added a comment - I've manged to create a minimalistic example (maven project) that illustrates what I'm seeing. You can run it with: "mvn jetty:run-war" Clicking the first save button / cancel link works (toolbar directly included in page). Clicking second save button results in the listener being triggered twice - the second cancel link does not do this, so I assume it is a h:commandButton "feature". I noticed that the nested component seemed to work properly if there was just one clientbehavior bound for the toolbar save button. In the actual code where I see the error, we have more than one client behavior bound - So I added a "Cancel" link with a clientbehavior to the sample project and then the Save button started resulting in double submits. I really hope this can get fixed as it makes it really hard to create building blocks for more complex pages.
          Hide
          chris_dezide added a comment -

          Hi, dug a little more into this.

          I'm pretty sure it is a mojarra bug as it works in myfaces and as the order of the unrelated <f:ajax> behaviors influences the faulty behavior (first defined behavior, screws up).

          This is really a big blocker for our project, not being able to create/use components with externalized ajax behavior totally destroys the component-oriented approach. Having to copy the same complex code/templates around for every component use, just to get different ajax behavior is a maintenance nightmare waiting around the corner.

          Anyway here are my findings:

          Original case from attached project
          <a:editor>
          	<f:ajax event="save" listener="#{backingBean.saveClicked}"/>
          	<f:ajax event="cancel" listener="#{backingBean.cancelClicked}"/>
          </a:editor>
          
          Results in:
          <input id="j_idt5:j_idt9:toolbar:saveBtn" type="button" onclick="jsf.util.chain(this,event,'mojarra.ab(this,event,\'action\',0,0)','mojarra.ab(this,event,\'action\',0,0)');return false" value="Save" name="j_idt5:j_idt9:toolbar:saveBtn">
          <a id="j_idt5:j_idt9:toolbar:cancelLnk" onclick="mojarra.ab(this,event,'action',0,0);return false" href="#">Cancel</a>
          

          Notice the jsf.util.chain chaining the same behavior twice.

          Behavior order swapped
          <a:editor>
          	<f:ajax event="cancel" listener="#{backingBean.cancelClicked}"/>
          	<f:ajax event="save" listener="#{backingBean.saveClicked}"/>
          </a:editor>
          
          Results in:
          <input id="j_idt5:j_idt9:toolbar:saveBtn" type="button" onclick="mojarra.ab(this,event,'action',0,0);return false" value="Save" name="j_idt5:j_idt9:toolbar:saveBtn">
          <a id="j_idt5:j_idt9:toolbar:cancelLnk" onclick="jsf.util.chain(this,event,'mojarra.ab(this,event,\'action\',0,0)','mojarra.ab(this,event,\'action\',0,0)');return false" href="#" name="j_idt5:j_idt9:toolbar:cancelLnk">Cancel</a>
          

          Notice that the faulty chaining now happens on the cancelLnk instead.

          Show
          chris_dezide added a comment - Hi, dug a little more into this. I'm pretty sure it is a mojarra bug as it works in myfaces and as the order of the unrelated <f:ajax> behaviors influences the faulty behavior (first defined behavior, screws up). This is really a big blocker for our project, not being able to create/use components with externalized ajax behavior totally destroys the component-oriented approach. Having to copy the same complex code/templates around for every component use, just to get different ajax behavior is a maintenance nightmare waiting around the corner. Anyway here are my findings: Original case from attached project <a:editor> <f:ajax event= "save" listener= "#{backingBean.saveClicked}" /> <f:ajax event= "cancel" listener= "#{backingBean.cancelClicked}" /> </a:editor> Results in: <input id= "j_idt5:j_idt9:toolbar:saveBtn" type= "button" onclick= "jsf.util.chain( this ,event,'mojarra.ab( this ,event,\'action\',0,0)','mojarra.ab( this ,event,\'action\',0,0)'); return false " value= "Save" name= "j_idt5:j_idt9:toolbar:saveBtn" > <a id= "j_idt5:j_idt9:toolbar:cancelLnk" onclick= "mojarra.ab( this ,event,'action',0,0); return false " href= "#" >Cancel</a> Notice the jsf.util.chain chaining the same behavior twice. Behavior order swapped <a:editor> <f:ajax event= "cancel" listener= "#{backingBean.cancelClicked}" /> <f:ajax event= "save" listener= "#{backingBean.saveClicked}" /> </a:editor> Results in: <input id= "j_idt5:j_idt9:toolbar:saveBtn" type= "button" onclick= "mojarra.ab( this ,event,'action',0,0); return false " value= "Save" name= "j_idt5:j_idt9:toolbar:saveBtn" > <a id= "j_idt5:j_idt9:toolbar:cancelLnk" onclick= "jsf.util.chain( this ,event,'mojarra.ab( this ,event,\'action\',0,0)','mojarra.ab( this ,event,\'action\',0,0)'); return false " href= "#" name= "j_idt5:j_idt9:toolbar:cancelLnk" >Cancel</a> Notice that the faulty chaining now happens on the cancelLnk instead.
          Hide
          Manfred Riem added a comment -

          Can you reproduce the problem with the latest 2.1 release?

          Show
          Manfred Riem added a comment - Can you reproduce the problem with the latest 2.1 release?
          Hide
          chris_dezide added a comment -

          Yes, the last release 2.1.20 also exhibits the faulty behavior.

          Show
          chris_dezide added a comment - Yes, the last release 2.1.20 also exhibits the faulty behavior.
          Hide
          Manfred Riem added a comment -

          Can you verify against the latest 2.1.22-SNAPSHOT?

          Available from https://maven.java.net/content/repositories/snapshots/org/glassfish/javax.faces/

          I am unable to reproduce it with that version.

          Thanks!

          Show
          Manfred Riem added a comment - Can you verify against the latest 2.1.22-SNAPSHOT? Available from https://maven.java.net/content/repositories/snapshots/org/glassfish/javax.faces/ I am unable to reproduce it with that version. Thanks!
          Hide
          chris_dezide added a comment -

          Hi,

          Just found the time to get the sample up and running with the snapshot repo.

          I still see the original error with the 2.1.22 snapshot as of now. I get the server-error below twice ( and the generated javascript still contains a chain that results in two attempted calls).

          And the snapshot seems even more broken, none of the event handlers are resolvable. Clicking a button yields:

          serverError: class javax.el.PropertyNotFoundException /index.xhtml @13,73 listener="#

          {backingBean.saveClicked}

          ": Target Unreachable, identifier 'backingBean' resolved to null

          Show
          chris_dezide added a comment - Hi, Just found the time to get the sample up and running with the snapshot repo. I still see the original error with the 2.1.22 snapshot as of now. I get the server-error below twice ( and the generated javascript still contains a chain that results in two attempted calls). And the snapshot seems even more broken, none of the event handlers are resolvable. Clicking a button yields: serverError: class javax.el.PropertyNotFoundException /index.xhtml @13,73 listener="# {backingBean.saveClicked} ": Target Unreachable, identifier 'backingBean' resolved to null
          Hide
          Manfred Riem added a comment -

          The way you have structured your nested component it will indeed trigger the listener multiple times as it will be added to both the editor and the toolbar.

          Show
          Manfred Riem added a comment - The way you have structured your nested component it will indeed trigger the listener multiple times as it will be added to both the editor and the toolbar.
          Hide
          chris_dezide added a comment -

          Hi,

          I can live with this feature being "by-design", but would you please explain how to obtain the behavior I expect in Mojarra?

          I want to create a composite component (the editor) which internally uses a toolbar component that is also used in other parts of the system.

          The behavior of the toolbar in an editor in a given page should be linked to methods in the backing bean for the page declaring the editor.

          • Or are you saying that Mojarra is not designed to fully support nesting of composite components?

          By the way my sample code works like I expect with MyFaces.

          Show
          chris_dezide added a comment - Hi, I can live with this feature being "by-design", but would you please explain how to obtain the behavior I expect in Mojarra? I want to create a composite component (the editor) which internally uses a toolbar component that is also used in other parts of the system. The behavior of the toolbar in an editor in a given page should be linked to methods in the backing bean for the page declaring the editor. Or are you saying that Mojarra is not designed to fully support nesting of composite components? By the way my sample code works like I expect with MyFaces.
          Hide
          Manfred Riem added a comment -

          In the top-level component pass it as an attribute defined in the editor, then in the editor pass it again then as a clientBehavior.

          Show
          Manfred Riem added a comment - In the top-level component pass it as an attribute defined in the editor, then in the editor pass it again then as a clientBehavior.
          Hide
          chris_dezide added a comment -

          Thank you for the quick response.

          I'm not familiar with any way of passing a "<f:ajax />" client behavior into a <f:attribute>,
          are you suggesting that I pass all the f:ajax attributes (potentially 7-8 per behavior I want to pass to inner component) manually?

          Btw. I can see that I managed to work around the issue by passing in the complete, configured toolbar using <cc:insertChildren/> and
          an attribute specifying the name of a javascript object that the behaviors collaborate with.

          I still think the behavior that myfaces exhibits, is the one that I would expect, but that may just be me.

          Show
          chris_dezide added a comment - Thank you for the quick response. I'm not familiar with any way of passing a "<f:ajax />" client behavior into a <f:attribute>, are you suggesting that I pass all the f:ajax attributes (potentially 7-8 per behavior I want to pass to inner component) manually? Btw. I can see that I managed to work around the issue by passing in the complete, configured toolbar using <cc:insertChildren/> and an attribute specifying the name of a javascript object that the behaviors collaborate with. I still think the behavior that myfaces exhibits, is the one that I would expect, but that may just be me.

            People

            • Assignee:
              Manfred Riem
              Reporter:
              chris_dezide
            • Votes:
              1 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: