Friday, February 12, 2016

Ajaxable Search Container Liferay

Ajaxable Search Container Liferay
Objective:  we are going to create a portlet which lists all the Liferay portal user using liferay-ui search container and making it ajaxable.
Here we are going to use liferay 6.2 EE (you can do it with CE as well) and inbuilt Alloy AUI JS .
Here I am starting with creating portlet and so on so if you are interested in knowing the magic code which makes it ajaxable then move to step 4.
Step 1

                Create a liferay plugin project  with name AjaxSearchContainer . so you will have one portlet entry in portlet.xml , change the view-template parameter to /html/ajaxsc/view.jsp.  Now Create an action class com.liferay.ajaxsc.UserListAction which extends MVCPortlet. 


Note: This step is intended for users who want to create same example which I am explaining here. So if you have any confusions in creating liferay plugin project you can go through the respective examples.

Step 2

            Now create init.jsp file to keep all you imports at one place and include it inside your view.jsp and also create  user_list.jsp file which will contain our search container.


Step 3

Concept: Here from our view.jsp we have created a div which will contain the dynamically loaded searchcontainer. On document ready we are making an ajax call which will hit the serveResource method in our Action Class and there we will prepare the SearchContainer object with results, delta etc and will set searchContainer object in request attribute and will  include user_list.jsp . In out user_list.jsp we will get that searchContainer object which will be used to populate Records.

Now  inside our view.jsp we  have created a div which will contain our searchcontainer . After  that we are doing an ajax call  which will be invoked on document ready i.e from aui ready context and ajax call will invoke searveResource Method   Below is the code. Here you can see in aui ready we are including two aui modules aui-base and aui-io-plugin-deprecated.
<%@ include file="init.jsp"%>
<portlet:resourceURL var="loadUsers"></portlet:resourceURL>
<div id="<portlet:namespace/>userList">
</div>
<aui:script>
AUI().ready('aui-base', 'aui-io-plugin-deprecated',function(A) {

            var userListCon = A.one('#<portlet:namespace/>userList');
            if(userListCon) {
                        userListCon.plug(
            A.Plugin.IO,
            {
                autoLoad: false
            }
        );
                        console.log("calling resource..")
                        userListCon.io.set('uri', "<%=loadUsers%>");
                userListCon.io.start();
            }          
});
</aui:script>

Step 4
            In our action class we are getting two parameters cur and delta where cur is current page and delta is items per page. In first call we will not have these parameters available so it will have default values current page 1 and delta 5. After that we are creating iteratorURL and After that we are creating SearchContainer Object with all necessary parameters. And ultimately setting that search container as request Attribute. Here is the code..

package com.liferay.ajaxsc;

import com.liferay.portal.kernel.dao.search.SearchContainer;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.portlet.LiferayWindowState;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.model.User;
import com.liferay.portal.service.UserLocalServiceUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;

import java.io.IOException;
import java.util.List;

import javax.portlet.PortletException;
import javax.portlet.PortletURL;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;

public class UserListAction extends MVCPortlet{
            Log _log = LogFactoryUtil.getLog(UserListAction.class.getName());


            @Override
            public void serveResource(ResourceRequest resourceRequest,
                                    ResourceResponse resourceResponse) throws IOException,
                                    PortletException {
                        _log.info("Getting Users..");
                        int cur = ParamUtil.getInteger(resourceRequest, "cur", 1);
                        int delta = ParamUtil.getInteger(resourceRequest, "delta", 5);
                        _log.info("cur: " + cur);
                        _log.info("delta: " + delta);
                        PortletURL iteratorURL = resourceResponse.createRenderURL();
                        iteratorURL.setWindowState(LiferayWindowState.NORMAL);
                       
                        SearchContainer<User> userListSearchContainer = new SearchContainer<User>(
                                                resourceRequest, null, null, "cur", cur, delta,
                                                iteratorURL, null, "No Users found.");
                        List<User> users = null;
                        int total = 0;
                        try {
                                    users = UserLocalServiceUtil.getUsers(userListSearchContainer.getStart(), userListSearchContainer.getEnd());
                                    total = UserLocalServiceUtil.getUsersCount();
                        } catch (SystemException e) {
                                    _log.error(e.getLocalizedMessage());
                        }
                       
                        userListSearchContainer.setResults(users);
                        userListSearchContainer.setTotal(total);
                        resourceRequest.setAttribute("userListSearchContainer", userListSearchContainer);
                        include("/html/ajaxsc/user_list.jsp", resourceRequest, resourceResponse);
                       
            }

}

In the above code we are including user_list.jsp.  So our search container will be available there as a request attribute.

Step 5
            In user_list.jsp we are getting that searchcontainer object from request attribute and populating searchcontainer.  For using liferay SearchContainer we have to import liferay-ui taglib which we have included in init.jsp as below

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@ taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui" %>
<portlet:defineObjects/>
<style scoped="scoped">

div.lfr-pagination-config {

display:none;
}
</style>
Now In final step we have to write Script which will help in pagination to work without refresh.
Here is our user_list.jsp

<%@page import="com.liferay.portal.kernel.dao.search.SearchContainer"%>
<%@page import="java.util.Enumeration"%>
<%@page import="com.liferay.portal.service.UserLocalServiceUtil"%>
<%@page import="com.liferay.portal.kernel.util.ParamUtil"%>
<%@page import="com.liferay.portal.model.User"%>
<%@page import="java.util.List"%>
<%@ include file="init.jsp"%>
<%
SearchContainer userListSearchContainer = (SearchContainer)request.getAttribute("userListSearchContainer");

%>
<liferay-ui:search-container searchContainer="<%=userListSearchContainer %>">
     <liferay-ui:search-container-results />
           <liferay-ui:search-container-row className="com.liferay.portal.model.User" modelVar="userModel">
                <liferay-ui:search-container-column-text name="Name" value="<%=userModel.getFullName() %>"></liferay-ui:search-container-column-text>
                <liferay-ui:search-container-column-text name="Email" value="<%=userModel.getEmailAddress()%>"></liferay-ui:search-container-column-text>
           </liferay-ui:search-container-row>
     <liferay-ui:search-iterator paginate="<%= true %>" />
</liferay-ui:search-container>

<aui:script use="aui-base,aui-io-plugin-deprecated">
   
    var userListContainer = A.one('#<portlet:namespace/>userList');
    var paginator = userListContainer.all('.taglib-search-iterator-page-iterator-bottom,.taglib-search-iterator-page-iterator-top,.lfr-pagination-page-selector,.lfr-pagination-delta-selector');

    if (userListContainer) {
        var parent = userListContainer;
        parent.plug(
            A.Plugin.IO,
            {
                autoLoad: false
            }
        );
        paginator.all('a').on(
            'click',
            function(event) {
                event.preventDefault();

                var uri = event.currentTarget.get('href');
                    
                     if(window.console && window.console.log) {
                    
                           console.log('original uri:', uri, event.currentTarget);
                     }   
               
                if (uri != 'javascript:;') {
                     uri = event.currentTarget.get('href').replace(/p_p_lifecycle=0/i, 'p_p_lifecycle=2');                 
                     if(window.console && window.console.log) {
                    
                         console.log('altered uri:', uri);
                         }

                     parent.io.set('uri', uri);
                     parent.io.start();
                 }
            }
        );
    }
</aui:script>


In the above javascript we are getting out container which we have created in view.jsp then we are getting all paginators inside that with their class . After that we have plugged the Input/output component with our container. Now we have bind click  event on pagination . So when user clicks on pagination we are replacing lifecycle value from 0 to 2 where 0 is for render phase and 2 is for resource phase so with this our pagination becomes  resource serving urls and they will invoke the serve resource method of our action class. Same process will repeat.


Note: you can see in init.jsp we have kept
                        

This will make our left side paginators hidden. Because this implementation is not supporting left side pagination.


Now we are done with all necessary steps we will check results

You can see the ajax loader clicking on next.
Hope this helps Thanks.

4 comments:

  1. I really appreciate information shared above. It’s of great help. If someone want to learn Online (Virtual) instructor lead live training in Liferay, kindly Contact MaxMunus
    MaxMunus Offer World Class Virtual Instructor led training on Liferay. We have industry expert trainer. We provide Training Material and Software Support. MaxMunus has successfully conducted 1,00,000 + trainings in India, USA, UK, Australlia, Switzerland, Qatar, Saudi Arabia, Bangladesh, Bahrain and UAE etc.
    For Demo Contact us.
    Akash Kumar Asthana
    MaxMunus
    E-mail: Nitesh@maxmunus.com
    Skype id: nitesh_maxmunus
    Contact No: 8553912023
    www.MaxMunus.com


    ReplyDelete
  2. I really appreciate information shared above. It’s of great help. If someone want to learn Online (Virtual) instructor lead live training in Liferay, kindly contact us http://www.maxmunus.com/contact
    MaxMunus Offer World Class Virtual Instructor led training on Liferay. We have industry expert trainer. We provide Training Material and Software Support. MaxMunus has successfully conducted 100000+ trainings in India, USA, UK, Australlia, Switzerland, Qatar, Saudi Arabia, Bangladesh, Bahrain and UAE etc.

    For Free Demo Contact us:
    Name : Arunkumar U
    Email : arun@maxmunus.com
    Skype id: training_maxmunus
    Contact No.-+91-9738507310
    Company Website –http://www.maxmunus.com


    ReplyDelete
  3. This is actually a great tutorial and this is easy way to add search container..thanks for sharing. We offers Liferay Java services. contact us for details.

    ReplyDelete