简体   繁体   中英

Weird behavior of JSF p:dataTable (first entry wrong in p:columns)

I have on a page two p:dataTable . The left one is mainly used for selection

<p:dataTable id="leftTable" var="item" value="#{bean.items}"
             selection="#{bean.item}" selectionMode="single">
  <p:ajax event="rowSelect" update=":rightTable" listener="#{bean.select}"/>  
  <p:column>
    <h:outputText value="#{item.value}" />  
  </p:column>
</p:dataTable>

This is fairly simple and works fine. The rightTable is a more complex one, this is a simplified example:

<p:dataTable id="rightTable" var="row" value="#{bean.rows}">
  <p:columns var="col" value="#{bean.cols}">  
    <h:outputText value="#{bean.map[row.id][col.id]}"/>
  </p:columns>
</p:dataTable>

Well, this also works fine. Now I implemented a composite component to replace the leftTable . This component also has selection and select attributes and in general is works, too. The same method like from p:dataTable is called and also the correct item is set.

But , and this is really a nasty thing: If I use my custom component, always the value in the first cell (column 0, row 0) is null . The values are taken from a Map<Long,Map<Long,String>> and I verified that the value for the specific row.id,col.id is set after the method is called.

I'm completely clueless stump with this issue and expect that it's really hard to answer this question and really appreciate if someone can even help me to debug this issue in more detail.

Upate 1 : By request I checked the #{row.id},#{col.id} :

95,626 | 95,528
96,527 | 96,528
97,527 | 97,528

In the first cell the col.id is wrong. It should be 527 but is actual 626 (it's the value of the previous request). Why does this happen? How can I get the correct value?

Update 2 : This is my component:

<composite:interface componentType="my.MenuDmClick">
  <composite:attribute name="actionListener" required="true"
        method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)"/>
  <composite:attribute name="selection"/>
  <composite:attribute name="update/>
  <composite:attribute name="dm"/>
</composite:interface>
<composite:implementation>
  <ui:repeat var="item" value="#{cc.attrs.dm.wrappedData}">
  <li>
    <p:commandLink actionListener="#{cc.actionListener(item)}"
                   update="#{cc.attrs.update}">
      <h:outputText value="#{item.name}"/>
    </p:commandLink>
  </li>
  </ui:repeat>
</composite:implementation>

And this is the backing bean:

@FacesComponent(value="my.MenuDmClick")
public class MenuDmClick extends UINamingContainer
{
  public void actionListener(Object ejb)
  {
    FacesContext context = FacesContext.getCurrentInstance();
    ValueExpression mSelection = this.getValueExpression("selection");

    if(mSelection!=null){mSelection.setValue(context.getELContext(), ejb);}
    else{throw new PropertyNotFoundException("'selection' must be a ValueExpression!");}

    MethodExpression ajaxEventListener =
         (MethodExpression) getAttributes().get("actionListener");
    ajaxEventListener.invoke(context.getELContext(), new Object[] {});
  }
}

After trying the usual stuff like

  • ui:repeat and c:forEach
  • immediate=true/false

I came across process=@this ... and it works like a charm!

<c:forEach var="item" items="#{cc.attrs.dm.wrappedData}">
  <li>
    <p:commandLink process="@this"
        actionListener="#{cc.actionListener(item)}" update="#{cc.attrs.update}">
      <h:outputText value="#{item.round.name}"/>
    </p:commandLink>
  </li>
</c:forEach>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM