Uploaded image for project: 'RichFaces'
  1. RichFaces
  2. RF-11134

ComponentIdResolver does not resolve clientId correctly

    Details

    • Type: Bug
    • Status: Resolved (View Workflow)
    • Priority: Major
    • Resolution: Won't Fix
    • Affects Version/s: 4.0.0.Final
    • Fix Version/s: None
    • Component/s: component-tables, core
    • Labels:

      Description

      Please consider the following test code:

      <rich:dataTable id="testTable" 
      	value="#{dataTableTestBackingBean.rowsModel}"
      	var="rowVar">
      	
      	<f:facet name="header">
      	   <rich:column>
      		<h:outputText value="Column 1" />
         	   </rich:column>
      	</f:facet>
      	
      	<rich:column>
      	   <h:inputText id="valTest" value="#{rowVar.col1}" >
             	 	<a4j:ajax 
             	 		event="blur" 
             	 		render="testColumn, footerTest" 
             	 		limitRender="true" 
             	 		execute="@this" />
      		</h:inputText>
      	</rich:column>
      	<rich:column>
      	   <h:outputText id="testColumn" value="#{dataTableTestBackingBean.footerValue}" />
      	</rich:column>
       
      	<f:facet name="footer">
      	   <rich:column>
      		<h:outputText id="footerTest" value="#{dataTableTestBackingBean.footerValue}" />
      	   </rich:column>
      	</f:facet>
       
      </rich:dataTable>
      
      

      This example will fail with the following Javascript error in the browser:

      Error: During update: formId:testTable:0:footerTest not found

      This is expected, b/c the correct id for the footer is formId:testTable:footerTest.

      The bug is in org.richfaces.context.ComponentIdResolver. Here is what happens:

      1. The RenderComponentCallback is executed on the input component ('valTest' in the example) and it reads the list of short ids to render from the attached Ajax Behavior. Note that we got here by walking the parent data table model, so the current rowKey is 0
      2. RenderComponentCallback asks ComponentIdResolver to resolve short ids into client IDs
      3. ComponentIdResolver starts ascending up the tree from 'valTest' and looking at facets and children until it finds 'footerTest'.
      4. At this point it asks for the clientId of 'footerTest' w/o regard for the fact that the data model has a rowKey that is set 0

      So, we get the wrong id b/c we call UiData.getClientId() outside of the normal walking order of that model.

      EDIT:
      I noticed that if I nest the above data table in another data iterator, then the footer update suddenly starts working. I investigated and it turned out that nested table will have getClientId() called on all of its components by the parent table, and since clientId s are cached, by the time ComponentIdResolver gets to it, it will use the cached id, rather than looking it up at the wrong time. Non-nested tables simply don't get around to calling getClientId() on their components before ComponentIdResolver runs, which is probably the real problem.

      Could it be an issue with the way UIDataAdapter.saveChildState(FacesContext facesContext) is written? Note that a nested table would save the state of its facets in saveChildState(FacesContext facesContext, UIComponent component), which would result in calls to getClientId() on the facet cells. A top level table would not save the state of the facets though, b/c we only traverse the children of the table inside UIDataAdapter.saveChildState(FacesContext facesContext)

        Gliffy Diagrams

          Attachments

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                vace117 Val Blant
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: