6/08/2011

jQuery, JSON and Liferay : One happy couple :)

From time to time you will have the requirement to load data asynchronously from a Liferay Service without having access to such nice technologies like ICEFaces or JSF in general. This post will show you how to use jQuery, JSON and AJAX to make such calls in a JSP portlet. Very, very useful !

Imagine the folllowing issue: Your customer tells you to implement two drop down lists: The first list contains all organizations in your Liferay environment, the second should contain the name of all users belonging to this organization. Your are not allowed to use JSF - just plain JSPs, enriched by AlloyUI, jQuery and JSON. Just a quick information before we begin: JSON is a very useful tool, that allows JAVA - Javascript conversion. This allows us to save a lot of time during development, because we don´t need to create converters. 

You could query the liferay database for all users, create tons of javascript objects and write some javascript methods that will remove and add elements to your SELECT boxes. This works for lilferay environments where there are very little users, but not for a standard enterprise environment. Here I would suggest doing the following:

We create a standard JSP page with two HTML SELECTs. The first one will be filled with all organizations that we find. When selecting an organization, a javascript method is triggered. This method calls a portlet method with the organization id as parameter. The backing method, retrieves all Users of that organization, converts the list of users to a JSON string and returns tis string to the portlet. The portlet iterates over this array and fills the second SELECT with OPTION elements. 

Step 1: Prepare the backend

Your portlet class should be a subclass of com.liferay.util.bridges.mvc.MVCPortlet. This allows you to implement the method "serveResource", which is specified in the JSF 286 specification. It allows you to access ressources of any kind in your portlet. One of the reasons why we use this method here is that it allows us to get a javascript representation of a java.util.List by using JSON. Here is the code:


@Override
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException {

//get the parameter
String organizationString = resourceRequest.getParameter("organizationId");

long orgId= Long.parseLong(organizationString);

try {
  //get all users of the organization
  List<User> organizationUsers = UserLocalServiceUtil.getOrganizationUsers(orgId);

  //let JSON do the conversion work
  String jsonString = JSONFactoryUtil.serialize(organizationUsers);
//write string to the output stream and we´re finished resourceResponse.getPortletOutputStream().write(jsonString.getBytes()); } catch (SystemException e) { e.printStackTrace();  } }


All the magic happens when calling JSONFactoryUtil.serialize : JSON creates a string representation of our list for us. This string is passed back to the portlet and that´s all we have to know for now.


Step 2: Implementing the onClick method

After the backend is ready and waiting for our calls, we will now implement the ajax call. Note that everything we do is working out of the box in Liferay 6 (didn´t test it on Liferay 5): no need to install anything else. So, here is the javascript code:
<portlet:resourceurl var="resourceUrl"></portlet:resourceurl>

<script language="JavaScript" type="text/javascript">

function fillUsers() {
  var select = document.getElementById("<portlet:namespace />orgSelect");
  var organizationId = select.options[select.selectedIndex].value;
  jQuery.get('<%=resourceUrl%>&organizationId='+organizationId,

function(data) { 

  var parsedJSONObject = jQuery.parseJSON(data); 
  var usersList = parsedJSONObject.list; 
  var usersSelect = document.getElementById("<portlet:namespace />usersSelect");
  //delete all old options
  usersSelect.length=0;
  for (var i =0; i < usersList.length; i++){
    var option = document.createElement("OPTION");
    option.text = ''+(usersList[i].fullName);
    option.value = ''+(usersList[i].userId); 
    usersSelect.options.add(optn); 
    }
  } 
);
}
</script>

Lets go through this. First, register a resource URL that is pointing to the method we created in our backend. This method is called by using jQuery.get() which fires an ajax request and calls the registered function when it receives an answer. After the data is received, a call to jQuery.parseJSON(data) parses the JSON string into a usable javascript object. This javascript object consists of a main node called "list" that contains all Users objects. You can now access these objects by calling their properties like this: usersList[i].fullName.

If you like this tutorial it would be very nice, if you could click on some of the google ads you see on the right side. It helps me run this block and motivates me ;)

If you have any questions, feel free to leave a comment.