Lazy loading Portlet

This is a solution to develop a portlet with a lazy loading mode. It is useful when you have a lot of portlets in your page and you don`t want to increase the loading time of the page. An interesting point is to save if the user closed or opened the portlet. Like that the next time he comes on the page the portlet will be open or close.

The following example doesn't load the content of the portlet until you click on the link on the portlet (you need JQuery in your portlet or your theme).

This is the code for our controller:

  • Method getPreferences to get a Boolean to know if the portlet has to be open or close. If it has to be open the portlet loads the data.
  • Method showMainView is to show the default view of the portlet (without the lazy loading data)
  • Method showDatasView is to make the display of the data loaded with ajax.
  • Method showDatas is to get the lazy loading data if it is not already done. And we save if the user has closed or opened the portlet.

Below, this is the controller class that implements this behaviour:

@Controller
@RequestMapping("VIEW")
public class LazyLoadingController{

    @ModelAttribute("portletIsClosed")
    public Boolean getPreferences(PortletRequest request) throws SystemException, PortalException {
           ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
	   PortalPreferences portalPreferences = PortletPreferencesFactoryUtil.getPortalPreferences(themeDisplay.getUserId(), themeDisplay.isSignedIn());
		
	   try{
	        return Boolean.valueOf(portalPreferences.getValue("NS-PORTLET-LAZY-LOADING", "portletIsClosed"));
	    }catch(Exception e){
		return false;
	    }
     }
	
     @RenderMapping
     public String showMainView(Model model, RenderRequest request, RenderResponse response) throws Exception {
            return "view";
     }
	
     @RenderMapping(params = "action=showDatas")
     public String showDatasView(Model model, RenderRequest request, RenderResponse response) throws Exception {
            return "list-datas";
     }
	
     @ActionMapping(params = "action=showDatas")
     public void showDatas(ActionRequest request, ActionResponse response, Model model, boolean portletIsClosed, boolean init) throws Throwable {
	    ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
	    PortalPreferences portalPreferences = PortletPreferencesFactoryUtil.getPortalPreferences(themeDisplay.getUserId(), themeDisplay.isSignedIn());
	    portalPreferences.getPortalPreferences(request).setValue("NS-PORTLET-LAZY-LOADING", "portletIsClosed", String.valueOf(portletIsClosed));
		
	    if(!init){
		 model.addAttribute("result", "Data loading by Ajax");
	    }
	    response.setRenderParameter("action", "showDatas");
     }
}

The view.jsp page to render the main page and implements the ajax call:

<portlet:actionURL var="ajaxURL" windowState="EXCLUSIVE">

       <portlet:param name="action" value="showDatas" />

</portlet:actionURL>

<script>

       var portletIsClosed = ${portletIsClosed};

       var init = false;

       // When you load the page

       $(document).ready(function() {

             if(!portletIsClosed){

                    showDatas();

             } else{

                    $('#listdatas').hide();

             }

       });

       // To get data and show them in the page if the portlet is opened

       function showDatas(){

             var container = $('#listdatas');

 

             if(portletIsClosed){

                    portletIsClosed = false;

                    container.show();

             } else if(!portletIsClosed && init){

                    portletIsClosed = true;

                    container.hide();

             }

            

             $.post( "${ajaxURL}", {portletIsClosed: portletIsClosed, init: init}, function( data ) {

                    if(!init){

                           container.html(data);

                           init  = true;

                    }

             });

       }

</script>

 

<style>

       #toggler{

             height: 20px;

             background-color: grey;

       }

</style>

 

<div id="main">

       <div id="toggler"><a href="#" onclick="showDatas()">My lazy loading portlet [open/close]</a></div>

       <div id="listdatas">

             <img src="${themeDisplay.pathThemeImages}/myTheme/img/loading.gif">

       </div>

</div>

 

The list-datas.jsp page to render only the html for the datas to include in the main page:

<div id="results">

       ${result}

</div>