Wednesday 14 August 2013

jQuery-UI Autocomplete

It enables users to quickly find and select from a pre-populated list of values as they type, leveraging searching and filtering.
jQuery-UI Autocomplete can be applied on any input field i.e. any HTML field of type <input> or on textarea i.e. <textarea>.

What jQuery-UI Autocomplete helps in?

It helps to achieve the intellisense or to display the available options to the user for a particular input field. Basically it acts as a plugin when integrated with any textbox, start searching for the matching records (filtering the records from the available or the provided source) and display it to the user for the selection. User can filter the records for better matches by entering more precise values. It also helps in achieving some functionality like on entering the district particular zip code is automatically filled in. Data source for the autocomplete can be local (present on the client side) or it can be remote (present on the server e.g. database).
Autocomplete also provide the user interaction with the list via keyboard also. So basically user can move up and down using arrow keys.

Applying styles on the Autocomplete box and the selection list

One can also customize the look and feel of the autocomplete textbox and the selection list. By default jQuery-UI CSS styles are used and one can modify it by extending the CSS classes (By extending I mean overwriting the styles in the applied classes)

Various Functionalities or Properties (Some of the frequently used properties) exposed by jQuery-UI autocomplete

  • Autofocus – If this property is set to “true” then the first item in the selection list is automatically selected when the options are shown.
  • Delay – On can set the delay required, this allows in configuring, after how much time the available options are shown in the selection list or the drop down which gets opened below the input field. So if the input is local then the filtration on the local data source is performed after the specified delay and then the filtered records are displayed. And if the data source is a remote data source then the server is made to get the filtered records from the database after the specified delay. It helps in preventing the frequent server hits to the server or minimizes the filtration processing if the data source is local. What actually happens is that if the delay is 1000ms and user keeps on entering the values(Characters) in the textbox then the server hit is made after the 1000ms when user stops entering the values.
  • Minlength – This property specifies, the minimum required characters that user should input to look out for the available options. So if it is et to 3 then the filtered records (If any record is present matching those characters depending upon your filtration criteria) are shown only when user enters three characters.
  • Position – Position of the selection list can be specified relative to the input field. Some of the available options are LeftTop, LeftBottom, RightTop, RightBottom. Position of the selection list can also be specified relative to the other elements present on the same mask.
  • Source – This is the actual data source of the options available to the user. It can be local or Remote, To specify the local data source one has to provide and array of items (Items can be just a string or can be an object with label and value properties, label if the property for the value which will be shown in the selection list or the drop down list whereas value is the property for the value or the string which will be shown inside the input field when user selects a particular option. If one of them is specified then it applies to both the properties). To specify the remote data source one has to give a URL string (which return the JSON data) to the source. The server can get the user entered value (On which the filtration can be performed on the server dynamically) in a query string parameter named “term” when an AJAX get request is made.



Various Methods exposed by jQuery-UI autocomplete

Some methods available help in controlling the selection list via Script (i.e. JavaScript or jQuery scripting). I will not go into too much details of it as they are self-explanatory (By their names) and not used very frequently as one rarely needs to play around with the Autocomplete box via script.
  • Close – This method is used to close down the auto complete selection list
  • Disable – This method disables the autocomplete feature on a input field
  • Enable – If you disable the autocomplete feature there must be some way to enable it, this is the method for achieving that.
  • Option (3 -Overloads) – One to get a specified option (By label. I hope you can now understand the difference between label and value in autocomplete), one to set the value of specified option, and one to get the whole option hash(i.e. the data source or one can say the filtered data source if user tried to filter it depending upon some input in the input box)
  • Search – You can forcefully make a search (May be on a click of some button present in your form) on a particular value or the value in the input field entered by user by the help of this method.



Various Events exposed or triggered by jQuery-UI autocomplete
These events will helps one in achieving custom functionalities or to do something on the back end  when user starts playing(or using) the control.
  • Change Event – As the name specifies and for the developers familiar with the JavaScript onchange event. This is triggered if focus is moved out and the value gets changed in the input field.
  • Close Event – This event is fired when the selection list or the drop down list showing the available option to the user is closed.
  • Create Event – This Event is fired on the creation of autocomplete much more like an init event. For those who are familiar with the init event they can easily use it but for those who don’t know about it, this is the event which every control exposes (independent if the technology) and is fired when the control is created.
  • Focus Event – This event is fired when a particular option in the selection list is focussed on by the user by using keyboard keys (Arrow keys up or down). Don’t confuse it with the on mouse hover. It is fired in case of keyboard interaction, is only fired when the user is focussing particular option by moving into the available option list up and down. It is not fired on selection. The default functionality attached to this event is to place the focussed option value into the input field or the text field.
  • Open Event – This event is fired whenever the new search is performed and the selection list is opened with the filtered items. So this event is also fired in the case when the search is performed and there are no suggested options which can be presented to the user. Consider that this event is fired in case of Updation of the filtered options (presented to the user).
  • Response Event – This event is fired when the search is performed before the available options are shown to the user. So if one want to manipulate the result set or write down some custom login to modify the result or to do anything before the result is shown to the user, this event is the best place.
  • Search Event – Once the user enters the minimum characters required to make a search then the search request is made to get the suggestion data(In case of delay mentioned search is made after delay interval from the mentioned scenario). So just before making the request to get the suggestion data Search event is fired. If one needs to do anything custom before making a request to get the suggestion data, this event is helpful.
  • Select Event – On this event by selected item from the selection list is populated to the input field or the text field and the selection list is closed. This is the default behaviour for this event. By user selection I mean that a user is traversing down the available options by keyboard keys and then presses enter to select a particular item or user selects an item from list via mouse click.

This is very much about the details of the jQuery-UI autocomplete; I think we can now go into the technical details of how we can implement it. I am guy from the .Net background (Using C#), so I am sorry but my implementation examples somehow will be in the same technology or language (especially the server side code showing the remote search). But it doesn’t mean that it will not work in Java Web forms (JSP) or may be some other pages. Here I will be presenting how it can be implemented in simple HTML pages.

Some of the prerequisites for using jQuery-UI Autocomplete:



  • jQuery Library – Can be downloaded from CDN(Content Delivery Network: http://code.jquery.com/jquery-1.9.1.js) or one can give link directly.
  • jQuery-UI Library - Can be downloaded from CDN(Content Delivery Network: http://code.jquery.com/ui/1.10.3/jquery-ui.js) or one can give link directly
  •  jQuery-UI CSS - Can be downloaded from CDN(Content Delivery Network: http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css) or one can give link directly
One can also use the minified version of all of these or any other version (Just make sure that they are using the required version of the dependent library).

Example of Local Data Source:

The HTML page complies with HTML5 standards

HTML:
<!doctype html>
<html>
<head>
    <title>Local Data Source Sample</title>
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
    <script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript" language="javascript"></script>
    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js" type="text/javascript"
        language="javascript"></script>
</head>
<body>
    <input id="txtTest" type="text" />
</body>
<script type="text/javascript"
        language="javascript">
    $("#txtTest").autocomplete({
        source: ["Test Value 1", "Test Value 2", "Test Value 3", "Unique Value"]
    });
</script>
</html>



Screenshot of the running sample:



This is a very simple example with the static data source.

Example of Remote Data Source

Here I will show you the use of some of the properties and events of the Autocomplete. We will make an AJAX request on the server to get the data on runtime in JSON format. Values from Client will be passed in the form of query string and HTTP Handler will be created to serve the request

HTML:

<!doctype html>
<html>
<head>
    <title>Remote Data Source Sample</title>
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
    <script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript" language="javascript"></script>
    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js" type="text/javascript"
        language="javascript"></script>
</head>
<body>
    <input id="txtTest" type="text" />
</body>
<script type="text/javascript" language="javascript">
    $("#txtTest").autocomplete({
        source: function (request, response) {
            $.ajax({
                url: "/default.Test",//Request is being made to the handler for extension test
                dataType: "json",
                data: {
                    term: request.term//You can also send more query string parameters here seperated by comma. request.term will send the value present in the textbox
                },
                success: function (data) {
                    if (data != null && data != '') {
                        response($.map(data, function (item) {
                            return {
                                label: item.FirstName + ' ' + item.LastName,
                                value: item.FirstName + ' ' + item.LastName //You can add more properties here
                            };
                        }));
                    } else {
                        $('ul[class*=ui-autocomplete]').hide();
                    }
                }
            });
        },
        minLength: 3,
        cache: false,
        select: function (event, ui) {
            if (ui != null && ui.item != null) {
                $("#txtTest").val(ui.item.value);
            }

            //The below code is written to prevent the execution of default button functionality on press of ENTER key
            var code = (event.keyCode ? event.keyCode : event.which);
            if (code == 13) {
                event.preventDefault();
                event.stopPropagation();
            }
            return false;
        }
    });
</script>
</html>

The sample is to get the users from the server and to show their first name and the last name in the selection list of autocomplete.
In the above sample you can see that the source is a function in which we are making an AJAX GET request to get the data from the server in JSON format. AJAX request is being made to the HTTP Handler with extension “*.Test”. The value which user entered in the textbox is passed as a query string parameter “term” and “request.term” helps us in getting the value present in the textbox and sent it to the server. If the Request is successful and we receive some data from the server then we return the array of object (Object contains two properties as we discussed earlier “label” and “value”, as of now both of these properties contain the First name and the last name separated by a space.)
I have used three properties and an event in the sample above.
  • Source – Discussed in the above paragraph
  • Minlength – Already Discussed
  • Cache
  • Select Event – Already Discussed


Cache is the property which helps in specifying that if the request needs to be made on the server again to get the data, or it can be served locally. So suppose there is a user “Abhishek Jain”, now if the user enters “abh” for the first time then server hit is made sending “abh” in the term query string and get the data. Now there is one suggested user “Abhishek Jain”. Now if the user deleted “abh” and enter something else another request will be made to the server, but if the user enters “abh” again in the textbox then the server hit is not made and the data which was fetched initially for “abh” will be shown. Other properties which I mentioned above can also be used in the similar way.
Now I will like to explain how to create a HTTP Handler, before starting it one should what is HTTP Handler and why I have created a handler in this case.

HTTP Handler:

HttpHandler is an extension based processor in other words pre-processing logic is executed depending on file extensions. So any request coming to the server for particular file extension will be served a particular handler for that extension. We can also create custom HTTP handlers to serve our request for a special extension. HTTP Handlers can be synchronous or asynchronous. My example will focus on how to create an Asynchronous HTTP handler.

Why I Created a HTTP Handler:

Actually I wanted to make an server request, either I can make it to a Web Method included in some page, or I can make that request to some service endpoint to get the data in JSON format, or as I have chosen to create and HTTP handler to server my request. My motive behind this is that whenever I want a similar kind of Autocomplete box; what I have done is I created a user control with this functionality so in any application of mine where I want a similar behaviour I can use that control and can just register this HTTP Handler for that side and the Autocomplete control will be running with the same functionality, although it can also be achieved with the help of Web Services or any other services but that will be a time consuming task and I don’t prefer to create a service just to return data for a autocomplete textbox.

How to create a HTTP Handler (specific to .Net)

First of all create a class defining the handler. In my scenario suppose “TestHandler.cs”. Now inherit that class from an interface “IHttpHandler” but in my case as I want an asynchronous HTTP handler so I will inherit it from “IHTTPAsyncHandler”. `Now here I have to implement three methods, two from IHttpAsyncHandler i.e. BeginProcessRequest and EndProcessRequest and third one from IHttpHandler i.e. ProcessRequest. This class will actually be creating a new operation instance (Operation is the entity which will actually be accomplishing the task and returning the result). I will explain in the next block how to create an Operation class or Entity. The Handler class will look like:

    public class TestHandler : IHttpAsyncHandler
    {
        #region Public Members

        /// <summary>
        /// Is reusable property of the handler
        /// </summary>
        public bool IsReusable { get { return false; } }

        #endregion

        #region IHttpAsyncHandler Members

        /// <summary>
        /// begin process request event fired on the starting of the handler request
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="asyncCallback"></param>
        /// <param name="extraData"></param>
        /// <returns></returns>
        public IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback asyncCallback, Object extraData)
        {
            IAsyncResult handlerResult = null;

            //Checks if the user is an authenticated user
            if (httpContext != null && httpContext.User != null && httpContext.User.Identity != null && httpContext.User.Identity.IsAuthenticated)
            {
                //Instance of Operation entity which will actually be accomplishing the task
                TestOperation testOperation = new TestOperation(asyncCallback, httpContext, extraData);
                testOperation.StartAsyncWork();
                handlerResult = testOperation;
            }
            return handlerResult;
        }

        /// <summary>
        /// end process request event fired on the end of the handler request
        /// </summary>
        /// <param name="result"></param>
        public void EndProcessRequest(IAsyncResult result)
        {
        }

        #endregion

        #region IHttpHandler Members

        /// <summary>
        /// Process Request, handle something which needs to be done on http contect request processing
        /// </summary>
        /// <param name="context"></param>
        public void ProcessRequest(HttpContext context)
        {

        }

        #endregion
    }



If you will like to have more details over the methods and properties which are present in this class please refer MSDN. This is out of the scope of my article

Now I will create an Operation class, looks like this:

    public class TestOperation : IAsyncResult
    {
        #region Private Members

        private bool completed;
        private Object state;
        private AsyncCallback callback;
        private HttpContext context;

        bool IAsyncResult.IsCompleted { get { return completed; } }
        WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } }
        Object IAsyncResult.AsyncState { get { return state; } }
        bool IAsyncResult.CompletedSynchronously { get { return false; } }

        #endregion

        #region CTOR

        /// <summary>
        /// Test operation constructor
        /// </summary>
        /// <param name="asyncCallback"></param>
        /// <param name="httpContext"></param>
        /// <param name="objectState"></param>
        public TestOperation(AsyncCallback asyncCallback, HttpContext httpContext, Object objectState)
        {
            callback = asyncCallback;
            context = httpContext;
            state = objectState;
            completed = false;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Starts Asynchronous work
        /// </summary>
        public void StartAsyncWork()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Starts the actual task
        /// </summary>
        /// <param name="workItemState"></param>
        private void StartAsyncTask(Object workItemState)
        {

            context.Response.ContentType = "application/json";
            context.Response.ContentEncoding = Encoding.UTF8;

            string searchBy = context.Request.QueryString[“term”] != null ?
                context.Request.QueryString[“term”] : string.Empty;
           
            string result = string.Empty;//Result string which will contain the result in JSON format

            //Get the data from the database or some other data source (Either get the filtered data using searchBy string or filter it here by using searchBy string)

            context.Response.Write(result);

            completed = true;
            callback(this);
        }

        #endregion
    }

With this we are done with the creation of handler, now build the project in which these two classes are present (DLL will be created which we will mention while registering the Handler for a particular site on the server)

Registration of the created handler on a particular site

There are two ways of registering it


  • Register it on IIS(Internet Information Server)
  • Do the registration via Web.Config file

Registering a Handler on IIS

Open IIS, Select you site under it and for that particular site open Handler Mapping section and click on Add Managed Handler



By this <Namespace> I mean is the full namespace of that class if any.
               
Registration via Web.Config

Open up the web.config file and make following handler mapping in the Handler section
<system.webServer>
    <handlers>
      <add name="TestHandler" path="*.Test" verb="*" type="<Namespace>.TestHandler" preCondition="integratedMode" />
    </handlers>
</system.webServer>


One this is done we are good to go and one can see the Autocomplete working with the Data from the server.

Hope this article is helpful. Please leave your comments and suggestions….

No comments:

Post a Comment