Implementing a collapsible ui:repeat rows in JSF

Wednesday December 19, 2012 ()

Here is simple implementation of a JSF <ui:repeat /> component with collapsible rows with the aid of JQuery.   It is very simple, no specials tricks, except that the components inside <ui:repeat /> must have a unique ID (or class) which is handled by the backing code.  Toggling the visibility of the frame (<div />) is taken cared of by the onclick event on the link, in this case <h:outputLink />

Even with PrimeFaces projects, there are cases/areas where you may want just a simple collapsible frame. This demonstration should answer that need.

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets">     
    <h:head>
        <title>Panel Visibility Toggle Demonstration</title>

        <link rel="stylesheet" 
              href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
        <script type="text/javascript"  
            src="http://code.jquery.com/jquery-1.8.3.js"></script>
        <script type="text/javascript"  
            src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>

        <script type="text/javascript" src="./js/toggle.js">
        </script>
    </h:head>

    <h:body >
        <ui:repeat value="#{collapsible.rows}" 
                   var ="rows">
            <h:panelGrid>
                <h:panelGroup>
                    <h:outputLink value="javascript:void(0)"
                                  onclick="vistoggle('#icon#{rows.id}',
                                          '#body#{rows.id}')" >

                        <h:outputText value="#{rows.title}" />
                    </h:outputLink>

                    <span style="display: inline-block;margin-right:2px;">
                        <span id="icon#{rows.id}" class="ui-icon ui-icon-plus" 
                              style="float:left">
                        </span>
                    </span> 
                </h:panelGroup>

                <div style="display:none;" id="body#{rows.id}">
                    #{rows.body}
                </div>
            </h:panelGrid>
        </ui:repeat>
    </h:body>
</html>                  

In the above page, we used plus (+)(ui-icon-plus) and minus (-) icons to indicate that the content is expanded and collapsed. These are jQuery UI icons. You may want to change it to suit your needs. Lines 8 to 12 are jQuery files. For PrimeFaces users, you may want to remove them.

All <div/> are initially collpased.  The ID of the frame takes any name and appended with a counter from the backing code, making the ID unique.

The class below represents the backing bean for our page. It is a standard JSF bean, List getRows () being the value of our <ui:repeat />


package info.kahimyang.tests;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped
public class Collapsible {

    public Collapsible() {
    }
    
    List<RepeatRows> rows;
    
    public List<RepeatRows> getRows () {                
        // populate rows
        return rows;
    }
    
    
    public void setRows (List<RepeatRows> s) {
        rows = s;
    }
    
    public class RepeatRows  {        
        RepeatRows () {}
                
        String id;
        String title;
        String body;
        
        // getters and setters
        public String getId () {
            return id;
        }
        public void setId (String s) {
            id=s;
        }
        // Other getters and setters
    }    
}


The JavaScript onclick handler

var prevIcon=null;
var prevPanel=null;
            
function vistoggle (icon, panel){
    if (prevPanel != null && panel != prevPanel) {
        $(prevPanel).hide('slow');        
    }                
    
    if($(panel).is(":visible")){
        $(panel).hide ('slow');
    }
    else {
        $(panel).show ('slow');
    }
    
    prevPanel=panel;
                
    if($(icon).hasClass("ui-icon-plus")){
        $(icon).removeClass("ui-icon-plus");
        $(icon).addClass("ui-icon-minus")
    }else{
        $(icon).removeClass("ui-icon-minus");
        $(icon).addClass("ui-icon-plus")
    } 
                
    if(prevIcon != null && icon!=prevIcon){        
        $(prevIcon).removeClass("ui-icon-minus");
        $(prevIcon).addClass("ui-icon-plus")        
    } 
    
    prevIcon=icon;
    
}          

Our onclick JavaScript handler takes the icon panel (span) and the panel (div) we want as collapsible. Please notice the use of removeClass and addClass. You can replace them with toggleClass if desired.

The icons may be removed completely, if not needed.

That's it Good Luck.


4,345

Comments (Implementing a collapsible ui:repeat rows in JSF)