Friday, May 30, 2014

Liferay Search Form with Search Container

Introduction:

Liferay Search form is Liferay UI component to design search form in liferay portlet development. This is simple JSTL tag we can use in JPS pages. In real time when we want implement search feature to portlet application then we can use the tag.

Generally we will use Search From with Liferay search container. We will enclose liferay search form in search container so that when we search data the result can be displayed in the grid.

Go through following link for more about search container


Liferay Search Form:

Search form we can enclose in the search container and it initially display single text box and we can design many input elements inside search form so that it will be inside toggle. We can open toggle and close

When we open toggle then we can see all input elements enclosed by the tag.

The following is declaration and we need pass jsp path there we will defined all input elements.


<liferay-ui:search-form
page="/html/jsps/student_search.jsp"
servletContext="<%= application %>"
/>


Search form as follows (/html/jsps/student_search.jsp)


<%@ include file="init.jsp" %>
<%
SearchContainer searchContainer = (SearchContainer)request.getAttribute("liferay-ui:search:searchContainer");
DisplayTerms displayTerms = searchContainer.getDisplayTerms();
%>
<liferay-ui:search-toggle
buttonLabel="Student Search"
displayTerms="<%= displayTerms %>"
id="toggle_id_student_search">
<aui:input label="First Name" name="firstName" value="<%=firstName %>" />
<aui:input label="Last Name" name="lastName" value="<%=lastName %>" />
<aui:input label="studentAge" name="studentAge" value="<%= studentAge %>" />
<aui:select name="studentGender">
<aui:option label="Male" value="1"></aui:option>
<aui:option label="Female" value="0"></aui:option>
</aui:select>
<aui:input label="studentAddress" name="studentAddress" value="<%= studentAddress %>" />
</liferay-ui:search-toggle>


Note:

We use toggle tag which will wrap the all the input elements.

Implementing Search with Search container

Generally in the development we will use search form with liferay search container and this tag will be enclose by search container tag one more thing  search container tag should be within form tag.

The following syntax


<aui:form>
<liferay-ui:search-container/>
<liferay-ui:search-form>
<liferay-ui:search-container-results/>
<liferay-ui:search-container-row/>
<liferay-ui:search-container-column-text/>
</liferay-ui:search-container-row>
<liferay-ui:search-iterator/>
</liferay-ui:search-container>
</aui:form>


Steps to implementation:
  1. Declare from tag with form create search container and its child tags.
  2. Implement search logic in respective Service Implementation class
  3. Pass search terms to Service method and fetch the result and pass to search container.

Declare from tag with form create search container and its child tags.

<aui:form>
<liferay-ui:search-container/>
<liferay-ui:search-form>
<liferay-ui:search-container-results/>
<liferay-ui:search-container-row/>
<liferay-ui:search-container-column-text/>
</liferay-ui:search-container-row>
<liferay-ui:search-iterator/>
</liferay-ui:search-container>
</aui:form>


Implement search logic in respective Service Implementation class

Based on search key word we need to implement logic in respective service implementation class.

Assume we are using Student data so we need to implement search logic in StudentLocalServiceImpl.java and we need run the service builder.

In the search we have implemented the Liferay Dynamic Query API and you can have more knowledge in Liferay wikis or liferay documentation.

The following is search implementation logic in StudentLocalServiceImpl.java


public class StudentLocalServiceImpl extends StudentLocalServiceBaseImpl {
public List getSerachStudents(String firstName,String lastName,int studentAge,int studentGender,String studentAddress,boolean andSearch, int start, int end, OrderByComparator orderByComparator)
throws SystemException
{
DynamicQuery dynamicQuery = buildStudentDynamicQuery(firstName, lastName, studentAge, studentGender, studentAddress, andSearch);
return StudentLocalServiceUtil.dynamicQuery(dynamicQuery, start, end, orderByComparator);
}

public int getSearchStudentsCount(String firstName,String lastName,int studentAge,int studentGender,String studentAddress,boolean andSearch)
throws SystemException
{
DynamicQuery dynamicQuery = buildStudentDynamicQuery(firstName, lastName, studentAge, studentGender, studentAddress, andSearch);
return (int)StudentLocalServiceUtil.dynamicQueryCount(dynamicQuery);
}

protected DynamicQuery buildStudentDynamicQuery(String firstName,String lastName,int studentAge,int studentGender,String studentAddress,boolean andSearch)
{
Junction junction = null;
if(andSearch)
junction = RestrictionsFactoryUtil.conjunction();
else
junction = RestrictionsFactoryUtil.disjunction();

if(Validator.isNotNull(firstName))
{
Property property = PropertyFactoryUtil.forName("firstName");
String value = (new StringBuilder("%")).append(firstName).append("%").toString();
junction.add(property.like(value));
}
if(Validator.isNotNull(lastName))
{
Property property = PropertyFactoryUtil.forName("lastName");
String value = (new StringBuilder("%")).append(lastName).append("%").toString();
junction.add(property.like(value));
}
if(studentAge > 0)
{
Property property = PropertyFactoryUtil.forName("studentAge");
junction.add(property.eq(Integer.valueOf(studentAge)));
}
if(studentGender > 0)
{
Property property = PropertyFactoryUtil.forName("studentGender");
junction.add(property.eq(Integer.valueOf(studentGender)));
}
if(Validator.isNotNull(studentAddress))
{
Property property = PropertyFactoryUtil.forName("studentAddress");
String value = (new StringBuilder("%")).append(studentAddress).append("%").toString();
junction.add(property.like(value));
}
DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(Student.class, getClassLoader());
return dynamicQuery.add(junction);
}
}


Pass search terms to Service method and fetch the result and pass to search container

Search URL:

We need search URL and it should carry search container JSP page otherwise it will navigate portlet default view page after search button click and it is simple liferay render URL.


<liferay-portlet:renderURL varImpl="studentSearchURL">
<portlet:param name="mvcPath" value="/html/jsps/student_search_container.jsp" />
</liferay-portlet:renderURL>


In the search form we have toggle open and close when we open toggle then we will input all search values so that our search logic fetch the result based on search terms.

We have two kind of search option in toggle one for match any key word and match all keywords.

Match ANY we will use OR operator in the search logic

Match ALL we will use AND operator in search logic

When we open toggle then it wills treats as Advance search and the result should be fetch based on all columns and its values with operators like AND/OR based on user input.

If the toggle off then there only input box so that user can give anything in the box then we will use this key word to search data on behalf of all columns in the table.

Calling of search method and fetch the data all the logic should be present inside search-container-result tag.

The following example code you can understand


<liferay-ui:search-container-results>
<%
DisplayTerms displayTerms =searchContainer.getDisplayTerms();
if (displayTerms.isAdvancedSearch()) {

total = StudentLocalServiceUtil.getSearchStudentsCount(firstName, lastName, 
 studentAge, studentGender, studentAddress,displayTerms.isAndOperator());
searchContainer.setTotal(total);
searchContainer.setResults(StudentLocalServiceUtil.getSerachStudents(firstName,
lastName,studentAge,studentGender,studentAddress,displayTerms.isAndOperator(), searchContainer.getStart(), searchContainer.getEnd(), new StudentNameComparator()));

}else {

String searchkeywords = displayTerms.getKeywords();
String numbesearchkeywords = 
Validator.isNumber(searchkeywords) ? searchkeywords : String.valueOf(0);

total = StudentLocalServiceUtil.getSearchStudentsCount
(firstName,lastName, studentAge, studentGender, studentAddress,displayTerms.isAndOperator());
searchContainer.setResults(StudentLocalServiceUtil.getSerachStudents
(searchkeywords,searchkeywords,Integer.parseInt(numbesearchkeywords),
Integer.parseInt(numbesearchkeywords), searchkeywords,false,
 searchContainer.getStart(), searchContainer.getEnd(), new StudentNameComparator()));
}

%>
</liferay-ui:search-container-results>


Iterator URL

We already know search container need iterator URL so that when we change the page it will use Iterator URL.

When we apply search we need to maintain all search keywords and its values as URL parameters otherwise search result will be changes.

For each page change it will get the search key words values from Iterator URL so that it can pass to respective search methods which are written inside search-container-result tag.


<liferay-portlet:renderURL varImpl="iteratorURL">
<portlet:param name="firstName" value="<%= firstName %>" />
<portlet:param name="lastName" value="<%= lastName %>" />
<portlet:param name="studentAge" value="<%= String.valueOf(studentAge) %>" />
<portlet:param name="studentGender" value="<%= String.valueOf(studentGender) %>" />
<portlet:param name="studentAddress" value="<%= String.valueOf(studentAddress) %>" />
<portlet:param name="mvcPath" value="/html/jsps/student_search_container.jsp" />
</liferay-portlet:renderURL>


Note:

We already implement search logic in respective service implementation class.

Complete code for Example

Search container JSP page (/html/jsps/student_search_container.jsp)


<%@page import="com.meera.dbservice.model.Student"%>
<%@page import="com.meera.liferaymvc.StudentNameComparator"%>
<%@page import="com.meera.dbservice.service.StudentLocalServiceUtil"%>
<%@ include file="init.jsp" %>
<a href="<portlet:renderURL />">&laquo;Home</a>
<div class="separator"></div>
<liferay-portlet:renderURL varImpl="studentSearchURL">
<portlet:param name="mvcPath" 
value="/html/jsps/student_search_container.jsp" />
</liferay-portlet:renderURL>
<aui:form action="<%=studentSearchURL %>"
method="get" name="studentForm">
<liferay-portlet:renderURLParams varImpl="studentSearchURL" />
<liferay-portlet:renderURL varImpl="iteratorURL">
<portlet:param name="firstName" value="<%= firstName %>" />
<portlet:param name="lastName" value="<%= lastName %>" />
<portlet:param name="studentAge"
value="<%= String.valueOf(studentAge) %>" />
<portlet:param name="studentGender" 
value="<%= String.valueOf(studentGender) %>" />
<portlet:param name="studentAddress"
value="<%= String.valueOf(studentAddress) %>" />
<portlet:param name="mvcPath" 
value="/html/jsps/student_search_container.jsp" />
</liferay-portlet:renderURL>
<liferay-ui:search-container
displayTerms="<%= new DisplayTerms(renderRequest) %>"
emptyResultsMessage="there-are-no-students"
headerNames="firstName,lastName,studentAge,
studentGender,studentAddress"
iteratorURL="<%= iteratorURL %>"
> 
<liferay-ui:search-form
page="/html/jsps/student_search.jsp"
servletContext="<%= application %>"
/>
<liferay-ui:search-container-results>
<%
DisplayTerms displayTerms =searchContainer.getDisplayTerms();
if (displayTerms.isAdvancedSearch()) {
total = StudentLocalServiceUtil.getSearchStudentsCount(firstName, 
lastName, studentAge, studentGender, 
studentAddress,displayTerms.isAndOperator());
searchContainer.setTotal(total);
searchContainer.
setResults(StudentLocalServiceUtil.getSerachStudents(firstName,
lastName,studentAge,studentGender,
studentAddress,displayTerms.isAndOperator(),
 searchContainer.getStart(), 
searchContainer.getEnd(), new StudentNameComparator()));
}else {
String searchkeywords = displayTerms.getKeywords();
String numbesearchkeywords = 
Validator.isNumber(searchkeywords) ? searchkeywords : String.valueOf(0);
total = StudentLocalServiceUtil.getSearchStudentsCount(firstName,lastName, 
 studentAge, studentGender, studentAddress,displayTerms.isAndOperator());
searchContainer.setResults(StudentLocalServiceUtil.
getSerachStudents(searchkeywords,
searchkeywords,Integer.parseInt(numbesearchkeywords),
Integer.parseInt(numbesearchkeywords), searchkeywords,false,
 searchContainer.getStart(), searchContainer.getEnd(),
new StudentNameComparator()));
}

%>
</liferay-ui:search-container-results>
<liferay-ui:search-container-row
className="Student"
keyProperty="studentId"
modelVar="currentStudent">
<liferay-portlet:renderURL varImpl="rowURL">
<portlet:param name="backURL" value="<%= currentURL %>" />
<portlet:param name="mvcPath" 
value="/html/jsps/display_student.jsp" />
<portlet:param name="redirect" value="<%= currentURL %>" />
<portlet:param name="studentId"
value="<%= String.valueOf(currentStudent.getStudentId()) %>" />
</liferay-portlet:renderURL>
<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="firstName"
property="firstName"
/>

<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="lastName"
property="lastName"
/>

<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="studentAge"
property="studentAge"
/>

<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="studentGender"
value='<%=currentStudent.getStudentGender()==1?"Male":"Female"%>'
/>

<liferay-ui:search-container-column-text
href="<%= rowURL %>"
name="studentAddress"
property="studentAddress"/>
</liferay-ui:search-container-row>
<liferay-ui:search-iterator searchContainer="<%=searchContainer %>" />
</liferay-ui:search-container>
</aui:form>


Search from JSP(/html/jsps/student_search.jsp)


<%@ include file="init.jsp" %>
<%
SearchContainer searchContainer = (SearchContainer)request.getAttribute("liferay-ui:search:searchContainer");
DisplayTerms displayTerms = searchContainer.getDisplayTerms();
%>
<liferay-ui:search-toggle
buttonLabel="Student Search"
displayTerms="<%= displayTerms %>"
id="toggle_id_student_search">
<aui:input label="First Name" name="firstName" value="<%=firstName %>" />
<aui:input label="Last Name" name="lastName" value="<%=lastName %>" />
<aui:input label="studentAge" name="studentAge" value="<%= studentAge %>" />
<aui:select name="studentGender">
<aui:option label="Male" value="1"></aui:option>
<aui:option label="Female" value="0"></aui:option>
</aui:select>
<aui:input label="studentAddress" name="studentAddress" value="<%= studentAddress %>" />
</liferay-ui:search-toggle>


Init.jsp page maintain all Tag lib URL declarations, Common Imports and Common Variables for all JSP pages

Init.jsp (html/jsps/init.jsp)


<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %><%@
taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %><%@
taglib uri="http://liferay.com/tld/security" prefix="liferay-security" %><%@
taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %><%@
taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %><%@
taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<portlet:defineObjects />
<liferay-theme:defineObjects />
<%
String currentURL = PortalUtil.getCurrentURL(request);
String firstName = ParamUtil.getString(request, "firstName");
String lastName = ParamUtil.getString(request, "lastName");
int studentAge = ParamUtil.getInteger(request, "studentAge");
int studentGender = ParamUtil.getInteger(request, "studentGender");
String studentAddress = ParamUtil.getString(request, "studentAddress");%>


Search Implementation service class (StudentLocalServiceImpl.java)


package com.meera.dbservice.service.impl;
import java.util.List;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
import com.liferay.portal.kernel.dao.orm.Junction;
import com.liferay.portal.kernel.dao.orm.Property;
import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.OrderByComparator;
import com.liferay.portal.kernel.util.Validator;
import com.meera.dbservice.model.Student;
import com.meera.dbservice.service.StudentLocalServiceUtil;
import com.meera.dbservice.service.base.StudentLocalServiceBaseImpl;
public class StudentLocalServiceImpl extends StudentLocalServiceBaseImpl {
public List getSerachStudents(String firstName,String lastName,int studentAge,int studentGender,String studentAddress,boolean andSearch, int start, int end, OrderByComparator orderByComparator)
throws SystemException
{
DynamicQuery dynamicQuery = buildStudentDynamicQuery(firstName, lastName, studentAge, studentGender, studentAddress, andSearch);
return StudentLocalServiceUtil.dynamicQuery(dynamicQuery, start, end, orderByComparator);
}

public int getSearchStudentsCount(String firstName,String lastName,int studentAge,int studentGender,String studentAddress,boolean andSearch)
throws SystemException
{
DynamicQuery dynamicQuery = buildStudentDynamicQuery(firstName, lastName, studentAge, studentGender, studentAddress, andSearch);
return (int)StudentLocalServiceUtil.dynamicQueryCount(dynamicQuery);
}

protected DynamicQuery buildStudentDynamicQuery(String firstName,String lastName,int studentAge,int studentGender,String studentAddress,boolean andSearch)
{
Junction junction = null;
if(andSearch)
junction = RestrictionsFactoryUtil.conjunction();
else
junction = RestrictionsFactoryUtil.disjunction();

if(Validator.isNotNull(firstName))
{
Property property = PropertyFactoryUtil.forName("firstName");
String value = (new StringBuilder("%")).append(firstName).append("%").toString();
junction.add(property.like(value));
}
if(Validator.isNotNull(lastName))
{
Property property = PropertyFactoryUtil.forName("lastName");
String value = (new StringBuilder("%")).append(lastName).append("%").toString();
junction.add(property.like(value));
}
if(studentAge > 0)
{
Property property = PropertyFactoryUtil.forName("studentAge");
junction.add(property.eq(Integer.valueOf(studentAge)));
}
if(studentGender > 0)
{
Property property = PropertyFactoryUtil.forName("studentGender");
junction.add(property.eq(Integer.valueOf(studentGender)));
}
if(Validator.isNotNull(studentAddress))
{
Property property = PropertyFactoryUtil.forName("studentAddress");
String value = (new StringBuilder("%")).append(studentAddress).append("%").toString();
junction.add(property.like(value));
}
DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(Student.class, getClassLoader());
return dynamicQuery.add(junction);
}
}


Download Search Container Portlet



Environment:

Liferay IDE 2.x+Eclipse (Kepler) +Liferay Plugins SDK 6.2+Tomcat 7.x Liferay Portal Bundle

Deployment and its Working.

Download portlet you can source or war file to deploy into liferay portal as your convenient.

Once portlet successfully deployed drag the portlet in any desired page. Portlet is available in sample category.

In the portlet page you can click on Student Search link then you can see the search container with search from.

Portlet Screens:

Default Page


Search Page



Search with toggle advanced search


Reference Links




Author

Recent Posts

Recent Posts Widget

Popular Posts