8 Replies Latest reply on Feb 6, 2009 7:49 AM by Ilya Shaikovsky

    reRender should be aware of  f:subview id prefix

    Francisco Jose Peredo Noguez Master

      Hi!
      reRender should be aware of the subview id prefixes, for example, if you have

      <f:subview id="idSubview1">
      <a:aRichControl="idOfRichControl">
      <a:commandButton id="commandButton" reRender = "idOfRichControl">
      </f:subview id="someSubview1">


      <f:subview id="idSubview2">
      <a:aRichControlid="idOfRichControl">
      <a:commandButton id="commandButton" reRender = "idOfRichControl">
      </f:subview id="someSubview1">

      Since we are using subview idSubview2.commandButton should reRender the idSubview2:idOfRichControl, but, instead of doing that it reRenders idSubview1:idOfRichControl, because it find it first in the page!

      If you know the subView name, this works:

      <a:commandButton id="commandButton" reRender = "idSubview2:idOfRichControl">

      but the problem is I am using subView to enable reutilization:

      <f:subview id="idSubView1">
      <ui:include src="SomeComponent.xhtml" />
      </f:subview>

      And some times i have several levels of subViews in top of SomeComponent.xhml, so there is no way to know beforehand what idPrefix will be generated for the controls inside it...

      The solution IMO would be something like:

      <a:commandButton id="commandButton" reRender = "#{currentSubViewIdPrefix}:idOfRichControl">

      but AFAIK a variable like that, dinamically storing the current SubView Id Prefix, is not available in JSF, Facelts or RichFaces...

      I think this is a bug, so I have posted it in JIRA (https://jira.jboss.org/jira/browse/RF-6039)

      Have you had to deal with this problem?

        • 1. Re: reRender should be aware of  f:subview id prefix
          Francisco Jose Peredo Noguez Master

          Oh, and BTW, I tried using a:region. Example:

          <a:region>
          <f:subview id="idSubView1">
          <ui:include src="SomeComponent.xhtml" />
          </f:subview>
          <a:region>

          and even tried with renderRegionOnly:

          <a:region renderRegionOnly="true">
          <f:subview id="idSubView1">
          <ui:include src="SomeComponent.xhtml" />
          </f:subview>
          <a:region>

          it did NOT help at all.

          Any hints?

          • 2. Re: reRender should be aware of  f:subview id prefix
            Francisco Jose Peredo Noguez Master

            I have investigated more, and according to richfaces docs the algorithm used to find the component to rerender is: UIComponent.findComponent().


            A search expression consists of either an identifier (which is matched exactly against the id property of a UIComponent, or a series of such identifiers linked by the NamingContainer.SEPARATOR_CHAR character value. The search algorithm should operates as follows, though alternate alogrithms may be used as long as the end result is the same:

            * Identify the UIComponent that will be the base for searching, by stopping as soon as one of the following conditions is met:
            o If the search expression begins with the the separator character (called an "absolute" search expression), 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.
            o Otherwise, if this UIComponent is a NamingContainer it will serve as the basis.
            o Otherwise, search up the parents of this component. If a NamingContainer is encountered, it will be the base.
            o Otherwise (if no NamingContainer is encountered) the root UIComponent will be the base.
            * 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:
            o 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).
            o If the search expression includes more than one identifier separated by the separator character, 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.



            From the description it seems to be aware of subViews (Naming Containers) but since it is actually not working there most be something wrong somewhere...

            In my app it is rerendering:

            Proyecto_equiposListSubView:empleadoSubView:empleadoTable:empleadoPanelList

            but what I want it to rerender is:

            Proyecto_equiposEditSubView:empleadoSubView:empleadoTable:empleadoPanelList


            As you can see the id is "almost the same" but it begins differently... (the top naming container changes)


            • 3. Re: reRender should be aware of  f:subview id prefix
              Francisco Jose Peredo Noguez Master

              Oh, and the command that triggers the rerendering looks like this:

              
              <a:commandButton id="search" value="Buscar" reRender="empleadoPanelList" action="#{empleadoList.buscar}">
               <f:param name="firstResult" value="0"/>
               </a:commandButton>
              
              


              As you can see I want to rerender empleadoPanelList, but the one inside the current subView (Proyecto_equiposEditSubView) not the one in the other subView (Proyecto_equiposListSubView)

              • 4. Re: reRender should be aware of  f:subview id prefix
                Francisco Jose Peredo Noguez Master

                Okey, lets see what do I know so far, I have a commandButton:


                
                <a:commandButton id="search" value="Buscar" reRender="empleadoPanelList" action="#{empleadoList.buscar}">
                 <f:param name="firstResult" value="0"/>
                 </a:commandButton>
                
                


                that (due to the structure of my page) ends up being:

                Proyecto_equiposListSubView:empleadoSubView:empleadoSearch:search

                I tell it to rerender empleadoPanelList, which ends up being:

                Proyecto_equiposListSubView:empleadoSubView:empleadoTable:empleadoPanelList

                but it reRenders, because it finds it first

                Proyecto_equiposEditSubView:empleadoSubView:empleadoTable:empleadoPanelList


                (I think I got confused in the previous posts saying the exact opposite thing)

                Now... why it finds the wrong one?

                I think the error is in the algorithm of UIComponent.findComponent():

                If the search expression does not begin with the the separator character then it searchs up the parents of this component. If a NamingContainer is encountered, it will be the base. In this case it finds: empleadoSearch, now, since empleadoPanelList is not inside empleadoSearch, I guess it goes up another level to the naming container: empleadoSubView, and here is where things get screwed up... it seems that findComponent looks both inside Proyecto_equiposListSubView:empleadoSubView and
                Proyecto_equiposEditSubView:empleadoSubView and it finds empleadoPanelList first in Proyecto_equiposEditSubView and reRenders that, instead of rerendering Proyecto_equiposListSubView:empleadoSubView.

                I guess the algorithm inside findComponent is not really designed the way it should be: it should give precedence to the empleadoSubView that is inside the same namingContainer where the commandButton is (Proyecto_equiposListSubView), and if it didnt find it there, go up another level, and only if is not there, try inside another root naming container.


                So, now... how to fix this? Maybe Richfaces should stop using UIComponent.findComponent? or should this be reported as a bug in the JSF/Mojarra issue tracker?



                • 5. Re: reRender should be aware of  f:subview id prefix
                  Francisco Jose Peredo Noguez Master

                  Mmm, I changed my code to reduce ambiguity.


                  CommandButton Id (rerenders incorrectly empleadoEditToListSubView:empleadoResultsList:empleadoPanelList
                  ):
                  Proyecto_equipoEditToListSubView:empleadoListToListSubView:empleadoSearch:search

                  Target rich:panel to rerender Id
                  Proyecto_equiposEditToListSubView:empleadoListToListSubView:empleadoResultsList:empleadoPanelList

                  CommandButton Id (rerenders correctly empleadoEditToListSubView:empleadoResultsList:empleadoPanelList
                  ):

                  Proyecto_equiposEditToEditSubView:empleadoEditToListSubView:empleadoSearch:search

                  Target rich:panel to rerender Id
                  Proyecto_equiposEditToEditSubView:empleadoEditToListSubView:empleadoResultsList:empleadoPanelList

                  Now, with this differences, I had the hope that the algorithm could work correctly... but no, since empleadoResultsList is inside both empleadoListToListSubView and empleadoEditToListSubView, the algorithm fails as before.

                  • 6. Re: reRender should be aware of  f:subview id prefix
                    Francisco Jose Peredo Noguez Master

                    If I do the following ugly hack it works:

                    <a:commandButton id="search" value="Buscar" reRender="empleadoListToListSubView:empleadoResultsList:empleadoPanelList" action="#{empleadoList.buscar}">
                     <f:param name="firstResult" value="0"/>
                     </a:commandButton>
                    


                    but that is not a solution, because that command button is inside a ui:composition that is used in many places, at many different subView depths. So the "right" idPrefix path changes dynamically...

                    My kingdom for a #{namingContainerPath}:


                    <a:commandButton id="search" value="Buscar" reRender="#{namingContainerPath}:empleadoPanelList" action="#{empleadoList.buscar}">
                     <f:param name="firstResult" value="0"/>
                     </a:commandButton>
                    


                    I guess almost nobody really reutilizes ui:composition components?

                    • 7. Re: reRender should be aware of  f:subview id prefix
                      Francisco Jose Peredo Noguez Master

                      Created issue 978 in Mojarra Issue Tracker.

                      It also seems that at least temporarly I will be able to workaround this becasue it only seems to "get lost" if it needs to go up 2 levels.

                      So all I have to do is use:

                      <a:commandButton id="search" value="Buscar" reRender="empleadoResultsList:empleadoPanelList" action="#{empleadoList.buscar}">
                       <f:param name="firstResult" value="0"/>
                       </a:commandButton>
                      


                      and since empleadoResultsList is is always there, it seems to work, of course, should also work without it, I hope they fix it for the next Mojarra release.

                      • 8. Re: reRender should be aware of  f:subview id prefix
                        Ilya Shaikovsky Master

                        thanks for your input. I've seens your issue in mojara mailing lists. will wait feedback from Jsf guys.