NeplatnyUdaj
NeplatnyUdaj

Reputation: 6242

JSF(Primefaces) update from within a table

I have a datatable which contain buttons deleting the rows and I'd like to refresh that table afterwards. The refreshing works fine except for a case when I remove the last item. I believe it's because of the rendered attribute, which misbehave on ajax update. It's all inside a composite component, the datatable is rendered conditionally and it all looks like this:

<p:dataTable id="#{cc.attrs.id2}_resultTable"
             value="#{cc.attrs.listData}"
             var="f"
             rendered="#{cc.attrs.list and not empty cc.attrs.listData}"
             rowKey="#{f.code}">
    ...columns
    <p:column>
        <p:commandButton action="#{myBB.removeItem}"
                         update="#{cc.attrs.id2}_resultTable">
            <f:setPropertyActionListener value="#{f}" target="#{myBB.selected}"/>
        </p:commandButton>
    </p:column>
</p:dataTable>

This works fine except the case when I remove the last item from the list(and want the table to disappear). Appearing of the table via ajax is not a problem because I'm adding items also without submit and the table appears correctly after adding the first item.

I tried to enclose the table in a h:panelgroup id="#{cc.attrs.id2}_resultPanel" with ID and updating this, but I get this exception:

Cannot find component with expression "test_resultPanel" 
referenced from "mainForm:j_idt111:test_resultTable:0:j_idt187".

I could maybe use the full path to the component, but that's a bit of a problem since it's a composite component.

The interesting think is, that the update works from the outside of the table. But when I move it to the column in the table, it doesn't.

Upvotes: 0

Views: 1426

Answers (1)

Daniel B. Chapman
Daniel B. Chapman

Reputation: 4687

NeplatnyUdaj probably has this right as to the cause, and it very well could be the rendered attribute. The solution I usually use to get around this is to simply create a set of wrapper objects and then refresh the whole table.

Your model could look like ->

  List<Wrapper> data = ....;
  public class Wrapper implements Serializable
  {
      properties....
     public void onAction(ActionEvent evt) { removeMeFromList(); //..do something }
  }

In the view you simply refer directly to the wrapper objects:

      <p:dataTable var="data" id="table"> ...
         <p:column>
           <p:commandButton actionListener="#{data.onAction}" update="table"/> 
           //Ajax updates here via the "Wrapper" object. 
           //Also, when there's complex business logic I find this 
           //easier to read (purely my preference).
         </p:column>
      ....

This isn't elegant but it is actually very easy to work with (and, if you're not concerned about having a lot of objects in memory it is an easy way to handle it). Because your action listener fires on the wrapper object you don't have to worry about when it fires, all the updates happen in the bean and then your table is updated with the new model.

In this case, I'd mark the rendered based on the size of the List, but that's all based on the implementation.

Good luck, hopefully this helps you.

Upvotes: 1

Related Questions