Sometimes you need to send or retreive data and update a small portion of portlet without a page refresh. Ajax is the solution to perform that and this tutorial will show how to use it in Liferay Portal.
Up to version 6.2 Liferay provides the JavaScript Framework AUI (AlloyUI). This framework can be used to perform the Ajax call. AUI was replaced by JQuery starting from the version 7.
In this tutorial, I will use MVCPortlet as Portlet Framework. The method serveResource of the MVCPortlet provides data like String, JSON, XML as response and is used to make Ajax call.
This tutorial will conver the main uses of Ajax call with both AlloyUI and JQuery:
Table of contents
AlloyUI
JQuery
The examples used in this tutorial are available on Github. Download the source
Prerequisites
Before seeing how to use Ajax in Liferay portlet, you need to understand Portlet namespace. Portlet namespace is a unique value generated and associated to each Portlet by the Portal. Namespacing avoids Portlet element to conflict with other Portlet elements having the same name. It ensures that the element name is uniquely associated with this portlet.
Why is this important ? Because if you don’t “namespace” parameters in your Ajax call, the Portal will not recognize them and simply ignore them. Liferay provides the taglib “portlet” to namespace parameters. To use it you must import the taglib to your JSP file as below:
1 |
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> |
Then you must prefix the html element you want to send to the server as following:
1 2 |
// parameter is namespaced. <portlet:namespace/>parameter : 'value' |
This solution can become very heavy especially if you have many parameters within your portlet. Another solution to avoid namespacing your parameters is by setting the property requires-namespaced-parameters to false in the liferay-portlet.xml
1 2 3 4 5 6 7 8 9 |
<portlet> <portlet-name>portlet-name</portlet-name> <icon>/icon.png</icon> <!-- Set this property to false to avoid namespacing parameters --> <requires-namespaced-parameters>false</requires-namespaced-parameters> <header-portlet-css>/css/main.css</header-portlet-css> <footer-portlet-javascript>/js/main.js</footer-portlet-javascript> <css-class-wrapper>portlet-name-portlet</css-class-wrapper> </portlet> |
With this Portlet configuration, parameters are recognized in the serveResource without prefixing them by <portlet:namespace/>.
In this tutorial, I will use the second solution. And let’s see now how to make Ajax call.
AlloyUI
-
Send data to the server
The JavaScript Framework AlloyUI provides the A.io.request method to perform the Ajax call. The first parameter concern the URL which will handle the request. In the Liferay context, you must provide a resourceURL as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> <portlet:defineObjects /> <!-- Defining the resourceURL --> <portlet:resourceURL var="sendData" /> <script type="text/javascript"> /* * Ajax call using AlloyUI. * On button click the serveResource is called with the submited data. */ function sendDataToServer(){ AUI().use( 'aui-io-request', function(A) { A.io.request( '<%=sendData%>', { method : 'post', // Sending three parameters. data : { firstname : 'Radouane', lastname : 'Roufid', site : 'www.roufid.com' } } ); } ); } </script> |
In the previous example, we used an Ajax call to send 3 parameters to the server using “post” method. Note that the parameters aren’t namespaced, in fact the property requires-namespaced-parameters is set to false in the liferay-portlet.xml. Below the configuration :
1 2 3 4 5 6 7 8 9 |
<portlet> <portlet-name>alloy-send-data</portlet-name> <icon>/icon.png</icon> <!-- Set this property to false to avoid namespacing parameters --> <requires-namespaced-parameters>false</requires-namespaced-parameters> <header-portlet-css>/css/main.css</header-portlet-css> <footer-portlet-javascript>/js/main.js</footer-portlet-javascript> <css-class-wrapper>alloy-send-portlet</css-class-wrapper> </portlet> |
If you want to namespace the parameters, set the property requires-namespaced-parameters to true and update the Ajax call as following:
1 2 3 4 5 6 |
// Sending three parameters. data : { <portlet:namespace/>firstname : 'Radouane', <portlet:namespace/>lastname : 'Roufid', <portlet:namespace/>site : 'www.roufid.com' } |
In server side, the data are retrieved from the resourceRequest in the serveResource method using ParamUtil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.roufid.tutorials; import java.io.IOException; import javax.portlet.PortletException; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.util.bridges.mvc.MVCPortlet; /** * Using Ajax in Liferay portlet tutorial. * * @author Radouane ROUFID. */ public class SendData extends MVCPortlet { @Override public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { // Retrieving the submitted data using ParamUtil. String firstname = ParamUtil.getString(resourceRequest, "firstname"); String lastname = ParamUtil.getString(resourceRequest, "lastname"); String site = ParamUtil.getString(resourceRequest, "site"); System.out.println("Firstname : "+ firstname); System.out.println("Lastname :" + lastname); System.out.println("Site : " + site); super.serveResource(resourceRequest, resourceResponse); } } |
-
Submit form to the server and receive response
Ajax is often used to submit forms to the server and receive response. Let’s see how to perform that.
Below an example of a very simple sum calculator : A form is displayed on the screen in which the client must fill two fields and submit it to perform the sum. The calculation is done in the server side and the result is displayed without a page refresh all using Ajax call.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> <portlet:defineObjects /> <!-- Defining the resourceURL --> <portlet:resourceURL var="submitForm" /> <script type="text/javascript"> function submitFormToServer(){ AUI().use( 'aui-io-request', function(A) { A.io.request( '<%=submitForm%>', { method : 'post', dataType: 'json', // Sending the form to the server. form : { id: 'calculator' }, // Receiving data from the server. Data is contained in this.get('responseData'). on: { success: function() { var response = this.get('responseData'); document.getElementById('result').innerHTML = response.result; } } } ); } ); } </script> <form id="calculator"> <div>Super calculator !</div> <br/> <table> <tr> <td><input type="text" name="firstInput"/></td> <td>+</td> <td><input type="text" name="secondInput"/></td> <td>=</td> <td><div id="result"></div></td> </tr> </table> <br /> <input type="button" value="Submit" onclick="submitFormToServer()"> </form> |
Note that the form is submitted by its id. In the server side, all the fields are retrieved by their name.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package com.roufid.tutorials; import java.io.IOException; import java.io.PrintWriter; import javax.portlet.PortletException; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.util.bridges.mvc.MVCPortlet; /** * Using Ajax in Liferay portlet tutorial. * * @author Radouane ROUFID. */ public class SubmitForm extends MVCPortlet { @Override public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { // Retrieving the submited data using ParamUtil. double firstInput = ParamUtil.getDouble(resourceRequest, "firstInput"); double secondInput = ParamUtil.getDouble(resourceRequest, "secondInput"); // Calculating the sum. double sum = firstInput + secondInput; // Creating a JSON object which will contain the sum. JSONObject jsonResponse = JSONFactoryUtil.createJSONObject(); jsonResponse.put("result", sum); // Writing the result in resourceResponse writer. PrintWriter writer = resourceResponse.getWriter(); writer.println(jsonResponse); } } |
Note that the sum is converted to a Json object and written in the resourceResponse.
The below image show the form before submission
Result after form submission:
The examples used in this tutorial are available on Github. Download the source
JQuery
JQuery is the default JavaScript Framework starting from the version 7 of Liferay. If you want to use it in the previous version rather that AlloyUI, you just need to include the library in your JSP file as below:
1 2 3 4 |
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %> ... <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> ... |
Below how to perform Ajax call in Liferay portlet.
-
Send data to the server
Same as AlloyUI, you need the use the JQuery Ajax call by specifing a resourceURL as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <portlet:defineObjects /> <!-- Defining the resourceURL --> <portlet:resourceURL var="sendData" /> <script type="text/javascript"> /* * JQuery Ajax call. * On button click the serveResource is called with the submited data. */ $(document).on('ready',function(){ jQuery('[id=send]').click(function(event) { $.ajax({ url:'<%=sendData%>', dataType: "json", data:{ firstname : 'Radouane', lastname : 'Roufid', site : 'www.roufid.com' } }); }); }); </script> <form> <input type="button" id="send" value="Send"> </form> |
In server side, the data are retrieved from the resourceRequest in the serveResource method using ParamUtil.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
package com.roufid.tutorials; import java.io.IOException; import javax.portlet.PortletException; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.util.bridges.mvc.MVCPortlet; /** * Using Ajax in Liferay portlet tutorial. * * @author Radouane ROUFID. */ public class SendData extends MVCPortlet { @Override public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { // Retrieving the submitted data using ParamUtil. String firstname = ParamUtil.getString(resourceRequest, "firstname"); String lastname = ParamUtil.getString(resourceRequest, "lastname"); String site = ParamUtil.getString(resourceRequest, "site"); System.out.println("Firstname : "+ firstname); System.out.println("Lastname :" + lastname); System.out.println("Site : " + site); super.serveResource(resourceRequest, resourceResponse); } } |
-
Submit form to the server and receive response
The same example as AlloyUI will be taken to perform a form submission using JQuery. A very simple sum calculator: A form is displayed on the screen in which the client must fill two fields and submit it to perform the sum. The calculation is done in the server side and the result is displayed without a page refresh all using Ajax call.
Below the client side code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <portlet:defineObjects /> <!-- Defining the resourceURL --> <portlet:resourceURL var="submitForm" /> <script type="text/javascript"> $(document).on('ready',function(){ jQuery('[id=submit]').click(function(event) { $.ajax({ url:'<%=submitForm%>', dataType: "json", data:{ data: $('#calculator').serialize() }, type: "post", success: function(data){ console.log(data); document.getElementById('result').innerHTML = data.result; } }); }); }); </script> <form id="calculator"> <div>Super calculator !</div> <br/> <table> <tr> <td><input type="text" name="firstInput"/></td> <td>+</td> <td><input type="text" name="secondInput"/></td> <td>=</td> <td><div id="result"></div></td> </tr> </table> <br /> <input type="button" id="submit" value="Submit"> </form> |
Note that the form submission is performed by $(‘#calculator’).serialize().Retrieving the data on the server side:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
package com.roufid.tutorials; import java.io.IOException; import java.io.PrintWriter; import javax.portlet.PortletException; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONObject; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.util.bridges.mvc.MVCPortlet; /** * Using Ajax in Liferay portlet tutorial. * * @author Radouane ROUFID. */ public class SubmitForm extends MVCPortlet { @Override public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException, PortletException { // Retrieving the submited data using ParamUtil. double firstInput = ParamUtil.getDouble(resourceRequest, "firstInput"); double secondInput = ParamUtil.getDouble(resourceRequest, "secondInput"); // Calculating the sum. double sum = firstInput + secondInput; // Creating a JSON object which will contain the sum. JSONObject jsonResponse = JSONFactoryUtil.createJSONObject(); jsonResponse.put("result", sum); // Writing the result in resourceResponse writer. PrintWriter writer = resourceResponse.getWriter(); writer.println(jsonResponse); } } |
Note that the sum is written is a Json object and written in the resourceResponse.
he below image show the form before submission
Result after form submission:
The examples used in this tutorial are available on Github. Download the source