14 Replies Latest reply on Apr 7, 2009 8:04 PM by fscan

    AJAX vs rendered bug

    msznapka.martin.sznapka.gmail.com

      Hello, I found some strange behaviour (probably bug) with AJAX and rendered attribute on other components.


      Imagine simple page where you have two EVENT scoped seam components (contentAround and contentHello). Data from contentAround are getting outside of the AJAX area and data from contentHello are getting only inside of the AJAX area.


      #{contentAround.hello}
      
      <a:commandLink reRender="HelloPanel" value="Hello link"/>
      <a:outputPanel id="HelloPanel">
          #{contentHello.hello}
      </a:outputPanel>
      
      #{contentAround.hello}
      
      <s:link value="Rendered link" rendered="#{contentAround.random}"/>
      



      So the behaviour of the framework should be like this:



      1. Loading page - creating and destroying both seam components (contentAround and contentHello)

      2. Clicking Hello link - creating and destroying only one component contentHello



      But the framework behaves differently in the second point - it creates both components, which is really strange.


      If you remove s:link, than everything works correctly, so I expect that the problem is in the rendered atrribute versus AJAX call.


      You can test this example on jboss-4.2.2.GA. Just copy example files to folder /jboss-seam-2.1.0.A1/examples/booking and deploy.

        • 1. Re: AJAX vs rendered bug
          mail.micke

          Not aswer to your question, more of a tip :)


          You may want to have a look at the a4j:region component, it provides some features (haven't used them all myself) which seems to be able to help delimiting what is processed on the server.


          Have a look at section 6.7 here RichFaces docs


          Cheers

          • 2. Re: AJAX vs rendered bug
            damianharvey.damianharvey.gmail.com

            Your commandLink will currently submit the entire form. If you want it to submit only itself, you need to use the ajaxSingle="true" attribute, or, as Mikael suggests, surround the commandLink with a region.


            Also, look into the limitToList attribute which will only send back in the response the elements listed in the attribute rather than anything that is in the region.


            IMO, ajaxSingle should be the default rather than the other way around.


            Cheers,


            Damian.

            • 3. Re: AJAX vs rendered bug
              msznapka.martin.sznapka.gmail.com

              Hi guys, thanks for your answers!


              Attributes ajaxSingle and limitToList doesn't solve the problem. The only and useless solution which works is at the end of this post.


              Anyway I still think that there is a bug in seam or ajax4jsf or facelets. Simply try my first post example and change


              <s:link value="Rendered link" rendered="#{contentAround.random}"/>
              



              to


              <s:link value="#{contentAround.random}"/>
              



              and everything works fine. Strange huh? So there IS bug in rendered attribute!


              .


              .


              .


              Here is the only and useless solution which i was speaking about above:


              <a:region renderRegionOnly="true">
                <a:commandLink reRender="HelloPanel" value="Hello link"/>
                <a:outputPanel id="HelloPanel">
                  #{contentHello.hello}
                </a:outputPanel>
              </a:region>
              



              I tried other possibilities like surrounding only commandlink with region, both separately with region, etc. Nothing of this was working.


              Moreover the above solution is unusable, because it doesn't support reRendering more components. So this code doesn't work:


              <a:region renderRegionOnly="true">
                <a:commandLink reRender="HelloPanel,HelloPanel2" value="Hello link"/>
                <a:outputPanel id="HelloPanel">
                  #{contentHello.hello}
                </a:outputPanel>
              </a:region>
              ...other HTML
              <a:region renderRegionOnly="true">
                <a:outputPanel id="HelloPanel2">
                  #{contentHello.hello}
                </a:outputPanel>
              </a:region>
              

              • 4. Re: AJAX vs rendered bug
                caye

                Martin, i guess you can't call to reRender the hello panel2 because is in another ajax region, so


                <a:region renderRegionOnly="true">
                  <a:commandLink reRender="HelloPanel,HelloPanel2" value="Hello link"/>
                  <a:outputPanel id="HelloPanel">
                    #{contentHello.hello}
                  </a:outputPanel>
                </a:region>
                ...other HTML
                <a:region renderRegionOnly="true">
                  <a:outputPanel id="HelloPanel2">
                    #{contentHello.hello}
                  </a:outputPanel>
                </a:region>
                



                never will work, why dont you try



                <a:region id="helloRegion" renderRegionOnly="true">
                  <a:commandLink reRender="helloRegion" value="Hello link"/>
                  <a:outputPanel id="HelloPanel">
                    #{contentHello.hello}
                  </a:outputPanel>
                
                  <a:outputPanel id="HelloPanel2">
                    #{contentHello.hello}
                  </a:outputPanel>
                </a:region>
                



                If you want it in another HTML page you can just do an include, it always works inside of the same region.


                If its too much problem or doesn't work at all, try to use the a4j:function and each time you call it you can find, reload or do whatever to you component and reRender the ajax part that you want (even call modal panels and so on).

                • 5. Re: AJAX vs rendered bug
                  msznapka.martin.sznapka.gmail.com

                  Why I am not using one a:region with a:commandlink and two a:outputpanel inside? ;) Simply because it doesn't solve my problem:


                  This code creates contentAround and contentHello:


                  <a:region renderRegionOnly="true">
                  
                    <a:commandLink reRender="HelloPanel,HelloPanel2" value="Hello link" ajaxSingle="true" limitToList="true"/><br/>
                  
                    <a:outputPanel id="HelloPanel">
                      #{contentHello.hello}
                    </a:outputPanel>
                            
                    <s:link value="Rendered link" rendered="#{contentAround.random}"/>
                            
                    <a:outputPanel id="HelloPanel2">
                      #{contentHello.hello}
                    </a:outputPanel>
                        
                  </a:region>
                  



                  This code creates ONLY contentHello:


                  <a:region renderRegionOnly="true">
                  
                    <a:commandLink reRender="HelloPanel,HelloPanel2" value="Hello link" ajaxSingle="true" limitToList="true"/><br/>
                  
                    <a:outputPanel id="HelloPanel">
                      #{contentHello.hello}
                    </a:outputPanel>
                            
                    <s:link value="#{contentAround.random}"/>
                            
                    <a:outputPanel id="HelloPanel2">
                      #{contentHello.hello}
                    </a:outputPanel>
                        
                  </a:region>
                  



                  Anyway, seems that you are all focusing on different solutions in ajax4jsf, but trust me, the problem is in RENDERED attribute:


                  Once again: Simply try my first post example and change


                  <s:link value="Rendered link" rendered="#{contentAround.random}"/>
                  



                  to


                  <s:link value="#{contentAround.random}"/>
                  



                  and you will see the difference.

                  • 6. Re: AJAX vs rendered bug
                    baspet

                    You must be sure that

                    #{contentAround.random}

                    evaluates to true. If contentAround is not in page or session scope, random property will be always false, since on restore view phase contentAround is reinitialized. Rerender attribute is the most painful attribute in JSF world because we expect that jsf will 'remember' the value assigned on render view phase..



                    • 7. Re: AJAX vs rendered bug
                      skidvd.seamframework.abilsoft.com

                      The rendered attribute can be tricky in an Ajax world.  Take a look at 5.3 of http://labs.jboss.com/file-access/default/members/jbossrichfaces/freezone/docs/devguide/en/pdf/richfaces-usersguide.pdf


                      Basically, if rendered evaluates to false, it will NOT reserve a place in the DOM structure for the subsequent Ajax request to update.  Therefore you must devise a placeholder for the eventual DOM update.  This is why the outputPanel is being suggested.

                      • 8. Re: AJAX vs rendered bug
                        damianharvey.damianharvey.gmail.com

                        I tried your code and changed ContentAround to be session scoped and the outcome is what you are after. You The logs only show


                        14:47:28,173 INFO  [STDOUT] ContentHello: Component creating
                        14:47:28,182 INFO  [STDOUT] ContentHello: Component destroying
                        
                        14:47:32,639 INFO  [STDOUT] ContentHello: Component creating
                        14:47:32,645 INFO  [STDOUT] ContentHello: Component destroying
                        


                        You could also investigate using the a4j:keepAlive tag, which does something similar (although it did keep destroying the ContentAround.)


                        Cheers,


                        Damian.


                        • 9. Re: AJAX vs rendered bug
                          msznapka.martin.sznapka.gmail.com

                          Thx for answers guys.


                          .


                          Vassilis Petropoulos, Damian Harvey:


                          Well yes, if you point rendered attribute to page or session scoped value, than everything works, but this solution is bad, because it is forcing me to higher level scope which i dont want in some cases.


                          .


                          Todd Gould:


                          Probably you mean chapter 5.4.1. Re-Rendering ;)
                          I read the chapter and the documentation is pointing to problem when you want reRender component which have also rendered attirbute (than the problem appears if the rendered will be false ;) - but that is not my example case, my example has rendered on different place.


                          .


                          I understand the reRender in AJAX4JSF like this:


                          Find JSF components subtree with UIComponent.findComponent() refresh this subtree and replace the subtree's HTML result on the page.


                          But WHY the ajax action in my example also call rendered attribute on component which is OUTSIDE the reRender area?

                          • 10. Re: AJAX vs rendered bug
                            pmuir

                            How about if you replace the <s:link> with a <h:commandLink>?

                            • 11. Re: AJAX vs rendered bug
                              msznapka.martin.sznapka.gmail.com

                              Nothing changed ;)


                              Doesn't matter if the component is s:link or h:commandLink, it is also not working with h:inputText ;(

                              • 12. Re: AJAX vs rendered bug
                                msznapka.martin.sznapka.gmail.com

                                Hi guys.


                                I think we should finish this discussion with simple fact:


                                It is good practise to put all rendered attribute values to PAGE scope (or higher scope) to avoid problems with refreshing this attribute during AJAX call.

                                • 13. Re: AJAX vs rendered bug
                                  msznapka.martin.sznapka.gmail.com

                                  Thank you all for your posts.

                                  • 14. Re: AJAX vs rendered bug
                                    fscan
                                    <blockquote>
                                    _Martin Sznapka wrote on Mar 17, 2008 22:37:_<br/>

                                    But *WHY* the ajax action in my example also call rendered attribute on component which is *OUTSIDE* the reRender area?
                                    </blockquote>

                                    i have the same problem ... i worte a custom jsf component which renders the subcomponents as a threaded message view. now, if the subcomponent is rerendered through a a:commandLink somewhere else on the site without the parent knowing about it, the "rowvar" does not get set and an error is thrown.

                                    my only solution is to wrap the other component (the one with the a:commandlink) in an a:region with renderRegionOnly=true.

                                    but i would really like to know why the ajax link, placed in another branch of the component tree tries to rerender the children of my components.