Liferay autocomplete example

Liferay autocomplete example

This tutorial I’ll show you how to create the autocomple with jQuery plugin with liferay portlet serve as backend code. The example was using flexjson 1.9.1 to serialize the object as json output string and you can download the source code here.


Note * Don’t mess up the jquery autocomplete with jquery ui autocomple plugin.

Sample JSON Data

{
  "members": [
     {"name":"Alex","id":1},
     {"name":"Agnes","id":2},
     {"name":"Alan","id":3},
     {"name":"John","id":4},
     {"name":"Jason","id":5},
     {"name":"Maria","id":6}
  ]
}

Member class

First, we create a member class with two attributes id and name, and then annotated the @JSON to the attribute for json result.

public static class Member {

	private String id;
        private String name;
	@JSON
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@JSON
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
}

MembersData class

Next, we create a wrapper class called MembersData with a list attributes members, so when we serialize this class into json it will generate the output like above example.

public static class MembersData {
     private List members;

     @JSON
     public List getMembers() {
	  return members;
     }

     public void setMembers(List members) {
          this.members = members;
     }
}

@ResourceMapping

In order to handling the asynchronize request, we used @ResourceMapping annotation handler the resource request. To get the value pass from ajax called we use PortletRequestUtils.getStringParameter.

@ResourceMapping
public void doAjax(ResourceRequest request,
	ResourceResponse response) throws Exception
{
     String term = PortletRequestUtils.getStringParameter(request, "term");
     PrintWriter out = response.getWriter();
     response.setContentType("json");
     response.setCharacterEncoding("utf-8");
     out.print(getRefreshData(term));
}

private String getRefreshData(String term) throws Exception {
     JSONSerializer serializer = new JSONSerializer();
     List resultset = new MemberDB().getData(term);

     MembersData  list = new MembersData();
     List members = new ArrayList();

     Member member;
     for(int i=0; i < resultset.size() ; i++){
	member = new Member();
	member.setId(String.valueOf(i));
	member.setName(resultset.get(i));
	members.add(member);
     }
     list.setMembers(members);
     return serializer.serialize(list);
}

Mock data 

Prepare the mock data from server side.

public class MemberDB {
       private int total;
       private String data =
             "Alex,Agnes,Alan,Bjok,Bill,John,Jason,Maria,Man";	

       private List members;

       public MemberDB() {
	    members = new ArrayList();
	    StringTokenizer st = new StringTokenizer(data, ",");

	    while(st.hasMoreTokens()) {
	 	members.add(st.nextToken().trim());
	    }
	    total = members.size();
	}

	public List getData(String query) {
	    String member = null;
	    query = query.toLowerCase();
	    List matched = new ArrayList();
	    for(int i=0; i < total; i++) {
	 	member = members.get(i).toLowerCase();
		if(member.startsWith(query)) {
	            matched.add(members.get(i));
		}
	    }
	    return matched;
	}
}

JSP & JQuery

Include the require library (jquery ui plugin)

<script src="${pageContext.request.contextPath}/js/jquery-1.4.2.min.js" type="text/javascript"></script>
 
<script src="${pageContext.request.contextPath}/js/jquery-ui-1.8.5.custom.min.js" type="text/javascript"></script>
 
<script src="${pageContext.request.contextPath}/js/jquery.ui.autocomplete.js" type="text/javascript"></script>
 
<link href="${pageContext.request.contextPath}/css/jquery-ui.css"
rel="stylesheet" type="text/css" />

Create a input fields for autocomplete and jquery to fire ajax event

<label>
        <span> Member : </span>
        <input type="text" id="member" name="member" />                                        
</label>  

//---- code omitted


<portlet:resourceURL var="jsonUrl" />   
<script type="text/javascript">  
       
$(document).ready(function() {    
      $("#member").autocomplete({
          source: function(request, response) {
            $.ajax({
                    url : ‘${jsonUrl}’,
                    dataType : ‘json’,
                    data : {
                        term : request.term
                    },
                    success : function(data) {
                        response($.map(data.members, function(item) {
                             return {
                                label: item.name,
                                value: item.name
                             }
                        }))
                    }
             })
           },
           minLength : 2,
           open: function() {
              $(this).removeClass("ui-corner-all").addClass("ui-corner-top");
           },
             
           close: function() {
              $(this).removeClass("ui-corner-top").addClass("ui-corner-all");
           }
       });
});
</script>

Label and Value

The plugin consists of label and value property.  Label property used to displayed the suggestion menu while, value property used to inserted into the input text field after selected.

//-- codeomitted

 response($.map(data.members, function(item) {
       return {
                label: item.name,
                value: item.name
        }
 }))

//-- codeomitted

Pass extra parameter to server

  <input type="text" id="member" name="member" />                    
  <input id="groupId" name="groupId" type="text" /> 

// --- codeomitted

  $.ajax({
         url : ‘${jsonUrl}’,
         dataType : ‘json’,
         data : {
         term : request.term,
         groupId: $("#groupId").val(); 
      },

Request object

A request object, with a single property called “term”, which refers to the value currently in the text input.

Response object

A response callback, which expects a single argument to contain the data to suggest to the user. This data should be filtered based on the provided term, and can be in any of the formats described above for simple local data (String-Array or Object-Array with label/value/both properties).

  $.ajax({
           url : ..........
      dataType : ............
          data : {
                 term : request.term
            },
       success : function(data) {
                 response(data)
          },
          .........
          .........
       });
    }

Term

It normally used as reference of the input textbox parameter. Request parameter “term”, will replace the value for autocomplete and added the value into the URL. For instance, the input textbox name=”firstname” the request parameter is not firstname, If you try to get request.getParameter(“firstname”) you will get undefined value. So, in your controller, you should get parameter(“term”) instead.

References

http://api.jquery.com/ajaxComplete/
http://wiki.jqueryui.com/Autocomplete
http://wiki.jqueryui.com/w/page/12137709/Autocomplete

6 comments

  1. Hi,

    Can you please provide a source code for this example?

    I really stuck with the @ResourceMapping, I am trying to return plain text as a response, But i can not get any response on a success callback function of jquery ajax.Instead of it, I got error “Syntax Error” on firfox browser’s error console.

    Please help on this.

    If you can provide the source code of this example then it would be really helpful for me.

    Reply
  2. Hi, source code was added.

    Reply
  3. Hi what if I have JSON data nested? such as this :
    {“list”: [
    {
    “id”: 10,
    “Name”: “Spiderman”,
    “Status”: “Untouchable”,
    “dept”: {
    “deptId” : 2,
    “deptName”: “SuperHuman”,
    “manager” : “The Avanger”
    }
    }, …. …
    ]}
    I want to display (name,deptName). Whats your suggestion?

    Rgds,

    Reply
  4. Hi,
    Can you explain return response
    [code]
    success : function(data) {
    response(jQuery.map(data.members, function(item) {
    return {
    label: item.id, // —-> I made changes
    value: item.name
    }
    }))
    }
    [/code]

    what if i want to display member ID to another input text based on selection on name in autocomplete?

    I try include as below :
    [code]
    select: function( event, ui ) {
    var x=$(‘#memberID’).val(ui.item.label);
    }
    [/code]

    but unfortunately it said ui.item.label is undefined. any trick here?

    Reply
  5. rendi, if your purpose is only for “display” like joining name + department. the most simple way to do this is pre-process the display information from your controller before you pass back to the jquery. Otherwise, you may need extra process to extract the json data into piece by piece before the return statement.

    Reply
  6. change succes function as

    success : function(data) {
                                response(jQuery.map(data.members, function(item) {
                                     return {
                                        label: item.name,
                                        value: item.name
                                        id   :  item.id
                                     }
                                }))
                            }
    add this 
    select : function(event, ui) {
          $("#hiddenfield").val(ui.item.id);
               },
    
    
    Reply

Leave a Reply to Pinkesh Gandhi Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.