Datatable onSelectComplete rendering detail datatable

UI Components for JSF
OrwTech
Posts: 8
Joined: 01 Jul 2010, 18:35

01 Jul 2010, 21:58

Hi

How do I make a single row selection in p:dataTable rerender a detail p:dataTable using onSelectComplete in a master-detail data relation using ajax postback?
The funtion that I am seeking is that when I select a row in the master table related detail record information must be displayed in the detail table.
In the show case samples has implemented displaying row details in a dialog using the dialog.show() and dialog.hide() methods in the onSelectComplete but I fail to find any methods on the DataTable widget allowing me to refresh my detailTbl widgetVar?

Is there any way to implement this?

I realize that I have to do somthing like this:

<p:dataTable id="masterTable" widgetVar="masterTbl" selection="#{myBean.masterModel}" .... onSelectComplete="detailTbl.<what method to call here on the widget?>" update="detailTable">
...
...
</p:dataTable>

<p:dataTable id="detailTable" widgetVar="detailTbl" selection="#{myBean.detailModel}">
...
...
</p:dataTable>

callahan
Posts: 768
Joined: 27 May 2010, 22:52

01 Jul 2010, 23:08

HI,

Here is a slightly modified version of the showcase example. The p:dialog is no longer there and the p:dataTables onselectComplete is no longer used. If you structure your page in a similar way, I think you'll get what you need.

Code: Select all

<h:form prependId="false">  
                       
    <p:dataTable var="car" value="#{tableBean.cars}" paginator="true" rows="10"  
        selection="#{tableBean.selectedCar}" selectionMode="single" update="display">  
        <p:column>  
            <f:facet name="header">  
                <h:outputText value="Model" />  
            </f:facet>  
            <h:outputText value="#{car.model}" />  
        </p:column>  
  
        <p:column>  
            <f:facet name="header">  
                <h:outputText value="Year" />  
            </f:facet>  
            <h:outputText value="#{car.year}" />  
        </p:column>  
  
    </p:dataTable>  
      
    <h:panelGrid id="display" columns="2">  
        <h:outputText value="Model:" />  
        <h:outputText value="#{tableBean.selectedCar.model}" style="font-weight:bold"/>  
              
        <h:outputText value="Year:" />  
        <h:outputText value="#{tableBean.selectedCar.year}" style="font-weight:bold"/>  
              
        <h:outputText value="Manufacturer:" />  
        <h:outputText value="#{tableBean.selectedCar.manufacturer}" style="font-weight:bold"/>  
             
        <h:outputText value="Color:" />  
        <h:outputText value="#{tableBean.selectedCar.color}" style="font-weight:bold"/>  
    </h:panelGrid>  
  
</h:form>

OrwTech
Posts: 8
Joined: 01 Jul 2010, 18:35

02 Jul 2010, 09:48

Hi bmacmanus

Thank you for your answer.

Mayby I need to add my sample of what I want to do.

The when clicking on a row on in the top table i want to lazy load data into the 2nd table.
Her I need a metod in:
onselectComplete="detailsTable.update();">


Code: Select all

        <h:form styleClass="jsfcrud_list_form">
            <p:dataTable widgetVar="masterTable" value="#{item.lazyModel}" var="item1" id="dataTable"  paginator="true" rows="10" lazy="true" dynamic="true" selectionMode="single" selection="#{item.item}"
                         rowsPerPageTemplate="5,10,20,50,100" paginatorTemplate="{PreviousPageLink} {CurrentPageReport} {NextPageLink} {RowsPerPageDropdown}"  page="#{item.page}" update="detailsTbl" onselectComplete="detailsTable.update();">
                    <p:column >
                        <f:facet name="header">
                            <h:outputText value="Id"/>
                        </f:facet>
                        <h:outputText value="#{item1.id}"/>
                    </p:column>
                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Name"/>
                        </f:facet>
                        <h:outputText value="#{item1.name}"/>
                    </p:column>
                    
                    <p:column>
                        <f:facet name="header">
                            <h:outputText escape="false" value="&nbsp;"/>
                        </f:facet>
                        <h:commandLink value="Show" action="#{item.detailSetup}">
                           
                        </h:commandLink>
                        <h:outputText value=" "/>
                        <h:commandLink value="Edit" action="#{item.editSetup}">
                            <f:setPropertyActionListener value="#{item1}" target="#{item.item}" />
                        </h:commandLink>
                        <h:outputText value=" "/>
                        <h:commandLink value="Destroy" action="#{item.destroy}">
                            <f:setPropertyActionListener value="#{item1}" target="#{item.item}" />
                        </h:commandLink>
                    </p:column>

                </p:dataTable>
                <p:messages/>
                <hr>
                <p:panel rendered="true">
                    <p:dataTable id="detailTbl" widgetVar="detailsTable" value="#{item.lazyDetailModel}" var="detail" dynamic="true" lazy="true" rows="10">

                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Value1"/>
                        </f:facet>
                        <h:outputText value="#{detail.value}"/>
                    </p:column>
                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Value2"/>
                        </f:facet>
                        <h:outputText value="#{detail.value2}"/>
                    </p:column>
                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Value3"/>
                        </f:facet>
                        <h:outputText value="#{detail.value3}"/>
                    </p:column>
                </p:dataTable>
                </p:panel>
            <br />

callahan
Posts: 768
Joined: 27 May 2010, 22:52

04 Jul 2010, 18:20

Hi,

I've looked at your code, but I still don't underdstand why it's necessary to manually update the details-table with Javascript after a row in the master-table is selected. The master-table uses the instant ajax row selection feature and should therefore be able to update the details-table automatically by specifying the id of the details-table component in the update attribute of the master-table component.

Your details-table is wrapped in a <p:panel rendered="true"> component. rendered is always set to true here, but if it ever happens to be false, the details-table will not be rendered. If the details-table is not rendered, it will not be physically present on the html page. If it's not physically present on the html page, it will be impossible to update it! Perhaps this is the source of the problems.

Here is an example that works with PrimeFaces 2.0.2. The master-table displays books, and the details-table displays authors.

Page:

Code: Select all

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.prime.com.tr/ui"
      xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
  </h:head>
  <h:body>
    <h:form prependId="false">
      <p:dataTable id="bookTable"
          value="#{bookAuthors.lazyBooks}"
          var="book"
          dynamic="true"
          lazy="true"
          selectionMode="single"
          selection="#{bookAuthors.currentBook}"
          update="authorsContent"
          paginator="true"
          rows="5"
          rowsPerPageTemplate="5,10,20,50,100"
          paginatorTemplate="{PreviousPageLink} {CurrentPageReport} {NextPageLink} {RowsPerPageDropdown}">

        <p:column>
          <f:facet name="header">
            <h:outputText value="Title"/>
          </f:facet>
          <h:outputText value="#{book.title}"/>
        </p:column>

        <p:column>
          <f:facet name="header">
            <h:outputText value="Text"/>
          </f:facet>
          <h:outputText value="#{book.text}"/>
        </p:column>

        <p:column>
          <f:facet name="header">
            <h:outputText value="Info"/>
          </f:facet>
          <p:commandLink value="Info" oncomplete="dlg.show();" update="bookDialogContent">
            <f:setPropertyActionListener value="#{book}" target="#{bookAuthors.currentBook}" />
          </p:commandLink>
        </p:column>

      </p:dataTable>

      <p:outputPanel id="authorsContent">
        <p:dataTable id="authorsTable"
            value="#{bookAuthors.currentBook.lazyAuthors}"
            var="author"
            dynamic="true"
            lazy="true"
            paginator="true"
            rows="5"
            rowsPerPageTemplate="5,10,20"
            paginatorTemplate="{PreviousPageLink} {CurrentPageReport} {NextPageLink} {RowsPerPageDropdown}">

          <p:column>
            <f:facet name="header">
              <h:outputText value="Name"/>
            </f:facet>
            <h:outputText value="#{author.name}"/>
          </p:column>

          <p:column>
            <f:facet name="header">
              <h:outputText value="Details"/>
            </f:facet>
            <h:outputText value="#{author.details}"/>
          </p:column>

        </p:dataTable>
      </p:outputPanel>
    </h:form>

    <p:outputPanel id="bookDialogContent">
      <h:form prependId="false">
        <p:dialog widgetVar="dlg" header="#{bookAuthors.currentBook.title}" id="bookAuthorsDialog" >
          #{bookAuthors.currentBook.title}
          <br/>
          #{bookAuthors.currentBook.text}
        </p:dialog>
      </h:form>
    </p:outputPanel>
  </h:body>
</html>
Bean:

Code: Select all

package controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import org.primefaces.model.LazyDataModel;

@SessionScoped
@ManagedBean
public class BookAuthors implements Serializable {
    private List<Book> _books = new ArrayList<Book>();
    private LazyDataModel<Book> _lazyBooks;
    private Book _currentBook;

    public BookAuthors() {
        for (int i = 0, k = 0; i != 100; i++) {
            List<Author> authors = new ArrayList<Author>();
            for (int j = 0; j != 20; j++, k++)
                authors.add(new Author("Author " + k, "Details for author " + k));

            _books.add(new Book("Book " + i, "Info about book " + i, authors));
        }

        _lazyBooks = new LazyDataModel<Book>(_books.size()) {
            @Override
            public List<Book> fetchLazyData(int first, int pageSize) {
                List<Book> lazyData = new ArrayList<Book>();
                for (int i = 0; i != pageSize; i++)
                    lazyData.add(_books.get(first + i));
                return lazyData;
            }
        };
    }

    public List<Book> getBooks() {
        return _books;
    }

    public void setBooks(List<Book> books) {
        _books = books;
    }

    public LazyDataModel<Book> getLazyBooks() {
        return _lazyBooks;
    }

    public Book getCurrentBook() {
        return _currentBook;
    }

    public void setCurrentBook(Book currentBook) {
        _currentBook = currentBook;
    }
}
Book:

Code: Select all

package controller;

import java.util.ArrayList;
import java.util.List;

import org.primefaces.model.LazyDataModel;

public class Book {
    private String _title;
    private String _text;
    private List<Author> _authors;
    private LazyDataModel<Author> _lazyAuthors;

    public Book(String title, String text, List<Author> authors) {
        _title = title;
        _text = text;
        _authors = authors;

        _lazyAuthors = new LazyDataModel<Author>(_authors.size()) {
            @Override
            public List<Author> fetchLazyData(int first, int pageSize) {
                List<Author> lazyData = new ArrayList<Author>();
                for (int i = 0; i != pageSize; i++)
                    lazyData.add(_authors.get(first + i));
                return lazyData;
            }
        };
    }

    public String getText() {
        return _text;
    }

    public void setText(String text) {
        _text = text;
    }

    public String getTitle() {
        return _title;
    }

    public void setTitle(String title) {
        _title = title;
    }

    public List<Author> getAuthors() {
        return _authors;
    }

    public void setAuthors(List<Author> authors) {
        _authors = authors;
    }

    public LazyDataModel<Author> getLazyAuthors() {
        return _lazyAuthors;
    }

    @Override
    public String toString() {
        return getTitle();
    }
}
Author:

Code: Select all

package controller;

public class Author {
    private String _name;
    private String _details;

    public Author(String name, String details) {
        _name = name;
        _details = details;
    }

    public String getName() {
        return _name;
    }

    public void setName(String name) {
        _name = name;
    }

    public String getDetails() {
        return _details;
    }

    public void setDetails(String details) {
        _details = details;
    }

    @Override
    public String toString() {
        return getName();
    }
}

maipucino
Posts: 112
Joined: 19 Apr 2010, 22:04

06 Jul 2010, 23:01

Hi,

I was having some issues with datatable's selection and find this thread. I tried the example posted here, books and authors, with 2.1.RC1-SNAPSHOT.
I am wondering why getCurrentBook() is called so many times when clicking on a book row. I can't find the logic behind that behavior.

Besides, the "info" link doesn't work properly: dialog shows details for any book, not the expected one.

Any suggestion ?.

maipucino
Posts: 112
Joined: 19 Apr 2010, 22:04

06 Jul 2010, 23:03

After downgrading to 2.0.2, "info" link works as expected. Seems to be a 2.1.RC1 issue.

callahan
Posts: 768
Joined: 27 May 2010, 22:52

07 Jul 2010, 13:44

I only tried the example out with PrimeFaces 2.0.2. Perhaps something needs to be migrated for it to work correctly in 2.1.

OrwTech
Posts: 8
Joined: 01 Jul 2010, 18:35

21 Jul 2010, 10:39

Hi callahan

Thank you for your sample - it works like expected but I cannot get my own code for layzy loading details to work. Maybe you can see the error?

Entity: Item2

Code: Select all

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controller;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;


@Entity
@Table(name = "ITEM2")
@NamedQueries({
    @NamedQuery(name = "Item2.findAll", query = "SELECT i FROM Item2 i"),
    @NamedQuery(name = "Item2.findById", query = "SELECT i FROM Item2 i WHERE i.id = :id"),
    @NamedQuery(name = "Item2.findByName", query = "SELECT i FROM Item2 i WHERE i.name = :name")})
public class Item2 implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @Column(name = "ID", nullable = false)
    private Long id;
    @Basic(optional = false)
    @Column(name = "NAME", nullable = false, length = 100)
    private String name;

    public Item2() {
    }

    public Item2(Long id) {
        this.id = id;
    }

    public Item2(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Item2)) {
            return false;
        }
        Item2 other = (Item2) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "controller.Item2[id=" + id + "]";
    }

}
Entity: Detail

Code: Select all

package controller;

public class Detail {
    public int value;

    public Detail(int value, int value2, long value3) {
        this.value = value;
        this.value2 = value2;
        this.value3 = value3;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue2() {
        return value2;
    }

    public void setValue2(int value2) {
        this.value2 = value2;
    }

    public long getValue3() {
        return value3;
    }

    public void setValue3(long value3) {
        this.value3 = value3;
    }
    public int value2;
    public long value3;
}
EntityFacade: (abstract class)

Code: Select all


package controller;

import java.util.List;
import javax.persistence.EntityManager;

public abstract class AbstractFacade<T> {
    private Class<T> entityClass;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity) {
        getEntityManager().persist(entity);
    }

    public void edit(T entity) {
        getEntityManager().merge(entity);
    }

    public void remove(T entity) {
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id) {
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<T> findRange(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

}
EntityFacade: Item2

Code: Select all

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controller;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 *
 * @author g95042
 */
@Stateless
public class Item2Facade extends AbstractFacade<Item2> {
    @PersistenceContext(unitName = "WebApplication2PU")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public Item2Facade() {
        super(Item2.class);
    }

}

Controller class: ItemController

Code: Select all

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package controller;

import java.util.List;
import java.util.ArrayList;
import java.util.Random;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.primefaces.model.LazyDataModel;

@ManagedBean(name="item")
@SessionScoped
public class ItemController {


    @EJB private controller.Item2Facade ejbFacade;
    private Item2 item = null;


    private Item2Facade getFacade() {
        return ejbFacade;
    }

    private LazyDataModel<Item2> lazyModel = new LazyDataModel<Item2>()
    {
            @Override
            public List<Item2> fetchLazyData(int first, int pageSize)
            {
                return getFacade().findRange(new int[]{first, first+pageSize});
            }

            @Override
            public int getRowCount() {
                return getFacade().count();
            }
     };

     private LazyDataModel<Detail> lazyDetailModel = new LazyDataModel<Detail>(3)
     {
            @Override
            public List<Detail> fetchLazyData(int first, int pageSize) {
                List<Detail> list = new ArrayList<Detail>();
                if (item != null)
                {
                    Random r = new Random(78338);
                    list.add(new Detail(r.nextInt(), r.nextInt(), System.currentTimeMillis()));
                    list.add(new Detail(r.nextInt(), r.nextInt(), System.currentTimeMillis()));
                    list.add(new Detail(r.nextInt(), r.nextInt(), System.currentTimeMillis()));
                }
                return list;
            }
     };

    public LazyDataModel<Detail> getLazyDetailModel() { return lazyDetailModel; }
    public LazyDataModel<Item2> getLazyModel() { return lazyModel; }
    //public void setLazyModel(LazyDataModel<Item2> lazyModel) { this.lazyModel = lazyModel; }
   
    public Item2 getItem() { return item; }
    public void setItem(Item2 item) { this.item = item; }
}

Finally the XHTML page:

Code: Select all

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.prime.com.tr/ui"
      xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
  </h:head>
        <h:body>
        <h1>Listing Item Items</h1>
        <h:form prependId="false">
            <p:dataTable value="#{item.lazyModel}" var="item1" id="dataTable" rows="5" paginator="true" lazy="true" dynamic="true" selectionMode="single" selection="#{item.item}"
                         rowsPerPageTemplate="5,10,20,50,100" paginatorTemplate="{PreviousPageLink} {CurrentPageReport} {NextPageLink} {RowsPerPageDropdown}"  update="dataTable,detailPanel">
                    <p:column >
                        <f:facet name="header">
                            <h:outputText value="Id"/>
                        </f:facet>
                        <h:outputText value="#{item1.id}"/>
                    </p:column>
                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Name"/>
                        </f:facet>
                        <h:outputText value="#{item1.name}"/>
                    </p:column>

                </p:dataTable>
                <p:messages/>
                <hr/>
                <p:panel id="detailsPanel">
                    <p:dataTable id="detailTbl" value="#{item.lazyDetailModel}" var="detail" dynamic="true" lazy="true" rows="10" >

                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Value1"/>
                        </f:facet>
                        <h:outputText value="#{detail.value}"/>
                    </p:column>
                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Value2"/>
                        </f:facet>
                        <h:outputText value="#{detail.value2}"/>
                    </p:column>
                    <p:column>
                        <f:facet name="header">
                            <h:outputText value="Value3"/>
                        </f:facet>
                        <h:outputText value="#{detail.value3}"/>
                    </p:column>
                </p:dataTable>
                </p:panel>
        </h:form>
        </h:body>
    </html>
When I select a row dataTable the the detailsPanel is refreshed but the setItem() nor the getLazyDetailModel() is never called in the ItemController until the entire form is submitted.

I have tried this code on 1.0.2 and 2.0.2 but the result remains the same.

callahan
Posts: 768
Joined: 27 May 2010, 22:52

22 Jul 2010, 00:33

I don't know if it's the source of the problem, but there is a typo in the update attribute of the master-table.

update="dataTable,detailPanel" should be
update="dataTable,detailsPanel"

Why are you updating dataTable? Would updating only detailsPanel not be enough.

OrwTech
Posts: 8
Joined: 01 Jul 2010, 18:35

22 Jul 2010, 08:29

Hi Callahan

You're my hero! Fixing the type made it all work fine :D
You are right there are no reason for updating dataTable

Thanx a lot!

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 19 guests