Simple expandable table with RichFaces

Expandable tables lets you click in a row to get more information about the particular record in this row. In this example, another rich:dataTable component is used to display details about one of the selected wonders.

screenshot01.png

Click on any [+]/[-] to expand/collapse any row:
screenshot02.png

JSF page:

<h:form>
   <rich:dataTable value="#{wonderBean.wonders}" var="wonder">
      <rich:column colspan="3">
         <f:facet name="header">Wonder</f:facet>
	 <h:outputText value="#{wonder.name}" />
	 <a4j:commandLink id="link" value="#{!wonderBean.show?'[+]':'[-]'}"
		reRender="link">
	 <a4j:actionparam name="val" value="#{!wonderBean.show}"
		assignTo="#{wonderBean.show}" />
	 </a4j:commandLink>
      </rich:column>
      <rich:columnGroup>
         <rich:column>
	    <a4j:outputPanel ajaxRendered="true">
	         <rich:dataTable value="#{wonder.details}" var="detail"
		    rendered="#{wonderBean.show}" style="border: 0px">
	            <rich:column>
			<f:facet name="header">Location</f:facet>
			<h:outputText value="#{detail.location}" />
		    </rich:column>
		    <rich:column>
		       <f:facet name="header">Image</f:facet>
		       <h:graphicImage value="#{detail.imageUrl}" />
		    </rich:column>
		 </rich:dataTable>
	      </a4j:outputPanel>
	   </rich:column>
        </rich:columnGroup>
     </rich:dataTable>
</h:form>

WonderBean class:

public class WonderBean {
   private WonderService service;
   private Boolean show;
 
   public Boolean getShow() { 
      return show;}
   public void setShow(Boolean show) {
	this.show = show;
   }
   public WonderService getService() {
	return service;
   }
   public void setService(WonderService service) {
	this.service = service;
   }
   public WonderBean() {
	super();	
   }
   public ArrayList<Wonder> getWonders() {
	return service.getList();
   }
}

WonderService class:

public class WonderService {
 
   private ArrayList <Wonder> list;
 
   public ArrayList<Wonder> getList() {
	return list;
   }
   @PostConstruct
   public void init () {
	list = new ArrayList <Wonder>();
	list.add(new Wonder("Chichen Itza", "Mexico", "http://upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Chichen-Itza-Castillo-Seen-From-East.JPG/90px-Chichen-Itza-Castillo-Seen-From-East.JPG"));
	list.add(new Wonder("Christ the Redeemer", "Brazil", "http://upload.wikimedia.org/wikipedia/commons/thumb/5/50/CorcovadofotoRJ.jpg/90px-CorcovadofotoRJ.jpg"));
	list.add(new Wonder("Colosseum", "Italy", "http://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Colosseum_in_Rome%2C_Italy_-_April_2007.jpg/90px-Colosseum_in_Rome%2C_Italy_-_April_2007.jpg"));
	list.add(new Wonder("Great Wall of China", "China", "http://upload.wikimedia.org/wikipedia/commons/thumb/1/16/GreatWallNearBeijingWinter.jpg/90px-GreatWallNearBeijingWinter.jpg"));
	list.add(new Wonder("Machu Picchu", "Peru", "http://upload.wikimedia.org/wikipedia/commons/thumb/1/13/Before_Machu_Picchu.jpg/90px-Before_Machu_Picchu.jpg"));
	list.add(new Wonder("Petra", "Jordan", "http://upload.wikimedia.org/wikipedia/commons/thumb/0/06/PetraMonastery.JPG/90px-PetraMonastery.JPG"));
	list.add(new Wonder("Taj Mahal", "India", "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Taj_Mahal_in_March_2004.jpg/90px-Taj_Mahal_in_March_2004.jpg"));		
	}
 
   public WonderService() {		
   }
}

Wonder class:

public class Wonder implements java.io.Serializable{
 
   private String name;
   private Details details;
 
   public String getName() {
	return name;
   }
   public void setName(String name) {
	this.name = name;
   }
   public Wonder(String name, String location, String imageUrl) {
	super();
	this.name = name;	
	this.details = new Details (location, imageUrl);
   }
   public Details getDetails() {
	return details;
   }
}

JSF configuration file:

<managed-bean>
  <managed-bean-name>wonderBean</managed-bean-name>
  <managed-bean-class>data.WonderBean</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
   <property-name>service</property-name>
   <property-class>data.WonderService</property-class>
   <value>#{service}</value>
  </managed-property>
 </managed-bean>
 <managed-bean>
  <managed-bean-name>service</managed-bean-name>
  <managed-bean-class>data.WonderService</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

24 comments

  1. davjo089

    Hi,
    How does the:
    rendered=”#{wonderBean.show}”
    show and hide only specific wonders? As the Boolean value is on the WonderBean and not connected to a specific Wonder, would it not show and hide all wonders?
    Thanks

  2. max

    By default an AJAX request sent from a particular row will limit the updates to that row only. For example, if all are closed and you click on one, only that row will be processed and updated (opened). So the property doesn’t need to be connected to any particular Wonder, it’s used by all the rows at a time. All RichFaces data iteration components support this feature. If you need to update more than one row, then you can use ajaxKeys attribute (http://is.gd/G2Zs). Also available on all data iteration components. Hope this helps.

  3. Jochen

    Hi Max,

    Thanks for this tutorial. It works fine at my side!
    But I have a question: I don’t want the empty row when the details are collapsed. So what I’ve tried:

    This doesn’t seem to work :-( … Can you help me out?

  4. Navin

    I have the problem with this code if it’s two level nested dataTable. This means if each of the location of the wonder has further data with it.

  5. Navin

    Max, my requirement is to use nested dataTables and of two-level expand. I find that innermost expand is not working at all.

  6. Rajasekhar

    Hi
    I tried above code it there is one problem if i click on icon it is not expanding aswell as it is not giving any java script error.

    application on Apache tomcat 6.0
    jsf1.2
    Rich Faces 3.2
    Eclipde Galylio
    the above mention is development environment.

    can you please help me on this issue. urgent

  7. Rajasekhar

    Hi
    I tried with RichFaces version 3.3.2 version still it is not working.
    Click on icon it is giving Object expected java script error.

    Please help me on this ASAP.

  8. max

    What is the exact error message, what browser are you using? Also, place a4j:log popup=”false” on a page and see if there are any errors in the log.

  9. Rajasekhar

    Hi,
    I am getting data from backent(Mainframes) now i have list of String objects.
    Using i am displaying the data but i need to make second colums as hyper link but i dont have control on particular column.because entaire list i am iterating at a time.

    How can i achieve this one please give the suggetions asap.

    tableHeader is the list it is coming from backend front end ppl dont know what it contains just we have to iterate and need to make second column as hyperlink

    Thnaks in advance.

  10. siva

    Hi Max,

    Thanks for this tutorial. It works fine at my side!
    But I have a question: I don’t want the empty row when the details are collapsed.

  11. M M Islam Chisty

    If you want to use pagination in both in your parent table and in your nested datatable, you will have to use rich:dataScroller, isn’t it? Givt it a try… see if it works at all … PRobably it will not work.

  12. Márcio Martins

    I had to make some adjustments… since it wasn´t retrieving only the respective wonder details:
    1. Put the Boolean attribute at the Wonder object (not the Wonderbean itself)
    2. Create a within the commandlink, setting the wonder object of the row to the bean where im going to retrieve the subtable
    3. Place a action in the commandlink =”#{WonderBean.getwonderdetails}”
    4. reRender the subtable

    thanks anyway.. it helped a lot

Leave a Reply