Liferay Search Container Sorting Example

The Liferay search container element provides the developers an easy way of implementing tabular representation of the data. The search container element supports pagination, ordering, and other capabilities and is part of the liferay-ui tag library.

Let’s create a simple search container to iterate and display the Employee details from the database. We will also add the sorting capabilities to different columns.

Version details: Liferay 6.2

Create the liferay portlet

Create a simple plugin project with an MVC portlet, as shown below. In this example, we have created a plugin portlet called the SearchContainerSort-portlet.

searchContainer1

Add the Service builder setup

Create a service.xml file, and add the following content to create an entity called EmployeeDetails as shown below, and run build service. To know more about the service builder tool, please visit the article about the service builder tool.

<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 6.2.0//EN" 
"http://www.liferay.com/dtd/liferay-service-builder_6_2_0.dtd">

<service-builder package-path="com.asb.sc"> 
  <author>ASB</author> 
  <namespace>Arun</namespace> 
  <entity name="EmployeeDetails" local-service="true" remote-service="false"> 
    <column name="empId" type="long" primary="true" /> 
    <column name="empName" type="String" /> 
    <column name="Dept" type="String" /> 
  </entity>
</service-builder>

Using search container UI element

To use the search container, we have to import the Liferay UI tag library into our jsp page.

<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>

Add the following code inside the view.jsp file. 

Here, we retrieve the orderByType and the orderByCol request parameters, that are passed from the search container to the render phase. These request parameters are passed every time we click on any of the column headers. These parameters are available on every render request.

Also, we are setting the values of the request parameters orderByType and orderByCol as asc and empName respectively.

The search container sorts the column based on the orderByType parameter value.

View.jsp

<%@page import="com.liferay.portal.kernel.util.ParamUtil"%>
<%@page import="com.liferay.portal.kernel.util.ParamUtil"%>
<%@page import="com.asb.sc.service.EmployeeDetailsLocalServiceUtil"%>
<%@page import="com.asb.sc.model.EmployeeDetails" %>
<%@page import="java.util.List" %>
<%@page import="java.util.ArrayList" %>
<%@page import="com.asb.sc.util.EmployeeDtlsComparatorUtil" %>
<%@page import="com.liferay.portal.kernel.util.ListUtil"%>
<%@page import="javax.portlet.PortletURL"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<portlet:defineObjects />

<h3>Orderable Search Container Example</h3>

<% PortletURL portletURL = renderResponse.createRenderURL(); 
portletURL.setParameter("jspPage", "/view.jsp"); 
String orderByCol = ParamUtil.getString(request, "orderByCol"); 
String orderByType = ParamUtil.getString(request, "orderByType"); 
if(orderByCol==null || orderByCol.equals("")) { 
   orderByCol="empName"; request.setAttribute("orderByCol",orderByCol); 
} if(orderByType==null || orderByType.equals("")) { 
   orderByType="asc";         
   request.setAttribute("orderByType",orderByType); 
} 
//Logic for toggle asc and desc on rendering the page 
if(orderByType.equals("desc")){     
   orderByType = "asc"; 
}else{     
   orderByType = "desc"; 
}%>
<liferay-ui:search-container orderByType="<%=orderByType%>" delta="3" 
   iteratorURL="<%=portletURL%>"> 
   <liferay-ui:search-container-results> 
    <% 
      List<EmployeeDetails> empList = EmployeeDetailsLocalServiceUtil.getEmployeeDetailses(-1, -1); 
      //Get a local copy so that it can be sorted based on our needs.
      List<EmployeeDetails> sortableUsers = new ArrayList<EmployeeDetails>
      (ListUtil.subList(empList, searchContainer.getStart(), searchContainer.getEnd())); 
      
      //Sort the list based on order and column:
      sortableUsers = EmployeeDtlsComparatorUtil.sortEmployeeDtls(sortableUsers, 
                       orderByCol, orderByType);     
      pageContext.setAttribute("results", sortableUsers);     
      pageContext.setAttribute("total", empList.size()); 
   %> 
  </liferay-ui:search-container-results> 
<liferay-ui:search-container-row className="com.asb.sc.model.EmployeeDetails" modelVar="empDtls" > 
   <liferay-ui:search-container-column-text property="empId" name="Employee Id" orderable="true" orderableProperty="empId"/> 
   <liferay-ui:search-container-column-text property="dept" orderable="true" orderableProperty="dept"/> 
   <liferay-ui:search-container-column-text property="empName" orderable="true" orderableProperty="empName"/> 
   </liferay-ui:search-container-row> <liferay-ui:search-iterator />
</liferay-ui:search-container>

We are using the custom class called EmployeeDtlsComparatorUtil to sort the list.

We are passing the object list to the method sortEmployeeDtls along with the column name and the order type.

Also, We are setting the results and the total attributes to the pageContext so that it will always be available for the search containers.

We are passing the entity class as the className attribute to the <liferay-ui:search-container-row> UI tag. Also, we are setting the modelVar that we can use for referring the entity value on each of the column item.

The <liferay-ui:search-container-column-text> UI tag is used to print the values of each column.

The below are few of the properties used.

property: Property name of the entity column.
orderable: Setting the value to true will enable the orderable property for that column.
orderableProperty: Property value, for which the sorting order should apply.
name: Name for the column.

Creating the comparator utillity class

Create a Util class called the EmployeeDtlsComparatorUtil and add the following code. Here we have different comparator implementations for each of the column with both ascending and descending order.

Based on the column and the order type, the search container component invokes the comparator methods.

package com.asb.sc.util;
package com.asb.sc.util;
import com.asb.sc.model.EmployeeDetails;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class EmployeeDtlsComparatorUtil {
 public static List<EmployeeDetails> sortEmployeeDtls(List<EmployeeDetails> empList, String orderByCol, String orderByType){ 
  if(orderByCol.equals("empName")) {     
   if(orderByType.equals("asc")) { 
    Collections.sort(empList, EmployeeDtlsComparatorUtil.empNameAsc);     
   }
   else {     
     Collections.sort(empList, EmployeeDtlsComparatorUtil.empNameDesc);     
    }     
  } 
  else if(orderByCol.equals("dept")) {     
   if(orderByType.equals("asc")) { 
    Collections.sort(empList, EmployeeDtlsComparatorUtil.empDeptAsc);     
   }else {     
    Collections.sort(empList, EmployeeDtlsComparatorUtil.empDeptDesc);     
   }
  }     
  else if(orderByCol.equals("empId")) {     
   if(orderByType.equals("asc")) { 
    Collections.sort(empList, EmployeeDtlsComparatorUtil.empIdAsc);     
   }else {     
    Collections.sort(empList, EmployeeDtlsComparatorUtil.empIdDesc);     
   }    
   } 
  return empList; 
} 

public static Comparator<EmployeeDetails> empNameAsc = new Comparator<EmployeeDetails>() { 
  @Override public int compare(EmployeeDetails o1, EmployeeDetails o2) { 
    EmployeeDetails empDtls1 = (EmployeeDetails) o1; 
    EmployeeDetails empDtls2 = (EmployeeDetails) o2; 
    int value = empDtls1.getEmpName().toLowerCase().compareTo(empDtls2.getEmpName().toLowerCase()); 
    return value; 
  }            
  // compare using attribute 1        
};         

public static Comparator<EmployeeDetails> empNameDesc = new Comparator<EmployeeDetails>() { 
  @Override public int compare(EmployeeDetails o1, EmployeeDetails o2) { 
   EmployeeDetails empDtls1 = (EmployeeDetails) o1; 
   EmployeeDetails empDtls2 = (EmployeeDetails) o2; 
   int value = empDtls2.getEmpName().toLowerCase().compareTo(empDtls1.getEmpName().toLowerCase()); 
   return value; 
  }        
};         

public static Comparator<EmployeeDetails> empDeptAsc = new Comparator<EmployeeDetails>() { @Override public int compare(EmployeeDetails o1, EmployeeDetails o2) { 
   EmployeeDetails empDtls1 = (EmployeeDetails) o1; 
   EmployeeDetails empDtls2 = (EmployeeDetails) o2; 
   int value = empDtls1.getDept().toLowerCase().compareTo(empDtls2.getDept().toLowerCase()); 
   return value; 
  }        
};         

public static Comparator<EmployeeDetails> empDeptDesc = new Comparator<EmployeeDetails>() { 
  @Override public int compare(EmployeeDetails o1, EmployeeDetails o2) { 
   EmployeeDetails empDtls1 = (EmployeeDetails) o1; 
   EmployeeDetails empDtls2 = (EmployeeDetails) o2; 
   int value = empDtls2.getDept().toLowerCase().compareTo(empDtls1.getDept().toLowerCase()); 
   return value; 
  }        
};                

public static Comparator<EmployeeDetails> empIdAsc = new Comparator<EmployeeDetails>() { 
 @Override public int compare(EmployeeDetails o1, EmployeeDetails o2) { 
   EmployeeDetails empDtls1 = (EmployeeDetails) o1; 
   EmployeeDetails empDtls2 = (EmployeeDetails) o2; 
   boolean value = empDtls1.getEmpId() > empDtls2.getEmpId(); 
   if(value){ 
      return 1; 
   } else { 
      return -1; 
   } 
  }        
};                
public static Comparator<EmployeeDetails> empIdDesc = new Comparator<EmployeeDetails>() { 
 @Override public int compare(EmployeeDetails o1, EmployeeDetails o2) { 
  EmployeeDetails empDtls1 = (EmployeeDetails) o1; 
  EmployeeDetails empDtls2 = (EmployeeDetails) o2; 
  boolean value = empDtls2.getEmpId() > empDtls1.getEmpId(); 
   if(value){ 
     return 1;
   } else { 
    return -1; 
   }
  }        
};
}

Testing the result

Finally, the output looks as shown below.

Sc2

Conclusion

In this article, we learned how to use the Liferay search container.

We also learned how to enable sorting capability for the table column of the search container UI component.

2 comments

  1. Great article, thanks. I just have a one question. Where should i put EmployeeDtlsComparatorUtil class in our portlet?

    1. Hi Adam,

      Glad you liked my post.

      You can put the EmployeeDtlsComparatorUtil class under a new util package, as it is a simple utility class. In this example i have added it under package : com.asb.sc.util.

Comments are closed.