Autocompletion Textbox in MVC Using jQuery


Ok, I have to admit it: jQuery is awesome.  If you haven’t started looking at it, I highly recommend that you do.  It works wonders in the ASP.NET MVC world.  One of the best things about jQuery is the enormous number of plug-ins that are available for adding even more functionality to the library.

The plug-in that I am going to be talking about in this post is jQuery Autocomplete

So let’s make a autocomplete text box in MVC for adding tags (or labels) for a blog post.  First, we are going to need to put a text box in one of our views with the name “tags”.

   1: <div>
   2:     <%= Html.TextBox("postTags")  %>
   3: </div>

Now, in the same view (or the master page) we need to add the references for jQuery Autocomplete.  The plug-in also comes with a stylesheet for styling the drop-down that will contain the autocomplete options.

   1: <link href="/Content/jquery.autocomplete.css" rel="stylesheet" type="text/css" media="screen" />
   2: <script type="text/javascript" src="/Scripts/jquery-1.2.6.js"></script>
   3: <script type="text/javascript" src="/Scripts/jquery.autocomplete.js"></script>

Next, we need to create a controller action that will return the list of autocomplete values in the JSON format. 

   1: [HandleError]
   2: public class UtilitiesController : Controller
   3: {
   4:     /// <summary>
   5:     /// This action method looks up the tags.
   6:     /// </summary>
   7:     /// <param name="q">The query that contains the user input.</param>
   8:     /// <param name="limit">The number of tags return.</param>
   9:     public ActionResult LookupTags(string q, int limit)
  10:     {
  11:         // We can get a list of tags from the database, but 
  12:         // for this example, I will populate a list with values.
  13:         List<string> tags = new List<string>();
  14:         tags.Add("asp");
  15:         tags.Add("mvc");
  16:         tags.Add("microsoft");
  17:         tags.Add("sql server");
  18:         tags.Add("jQuery");
  19:         tags.Add("ajax");
  20:  
  21:         // Select the tags that match the query, and get the 
  22:         // number or tags specified by the limit.
  23:         var retValue = tags
  24:             .Where(x => x.StartsWith(q))
  25:             .OrderBy(x => x)
  26:             .Take(limit)
  27:             .Select(r => new { Tag = r });
  28:  
  29:         // Return the result set as JSON
  30:         return Json(retValue);
  31:     }
  32: }

Finally, we have to add the jQuery Autocomplete initialization script in the view (or master page) to wire up the plug-in to the text box.  Notice in line 4 that we are using a the action method that we created above to get the list of tags.

   1: <script type="text/javascript">
   2: $(document).ready(function() 
   3: {
   4:     $("#postTags").autocomplete('<%=Url.Action("LookupTags", "Utilities") %>', 
   5:     {
   6:         dataType: 'json',
   7:         parse: function(data) 
   8:         {
   9:             var rows = new Array();
  10:             for (var i = 0; i < data.length; i++) 
  11:             {
  12:                 rows[i] = { data: data[i], value: data[i].Tag, result: data[i].Tag };
  13:             }
  14:             return rows;
  15:         },
  16:         formatItem: function(row, i, max) 
  17:         {
  18:             return row.Tag;
  19:         },
  20:         width: 300,
  21:         highlight: false,
  22:         multiple: true,
  23:         multipleSeparator: ","
  24:     });
  25: });
  26: </script>

The documentation for the plug-in details all of the various options that can be used in the autocomplete function.

Now we have an AJAX enabled autocomplete box using jQuery in ASP.NET MVC.

image

The power of jQuery never ceases to amaze me.  There will likely be plenty more posts to come on the topic of using jQuery in MVC.

Comments (30)

  1. #.think.in says:

    #.think.in infoDose #7 (10th Nov – 15th Nov)

  2. Frank says:

    Do u mind published your project on web, and we can download it

    thanks

  3. jitendra says:

    how to integrate your code in webservice in asp.net i have tried it but i am unable to do it. and what will come here

    (‘<%=Url.Action("LookupTags", "Utilities") %>

  4. Janus Knudsen says:

    The concept of autocomplete is clear, but unfortunately the details here is blurred.

    Well… actually I think it’s a nice example, but it would be even better if you would drill down into the details of Url.Action, also <%= Html.TextBox("tags")  %> is called postTags in your autocomplete function.

  5. Janus Knudsen: Thanks for pointing out the "tags" naming problem.  That has been updated.

    What details exactly are you looking for about the Url.Action piece?

    Thanks for the comments.

  6. Janus Knudsen says:

    Url.Action is a piece of the MVC afaik 🙂 I was just wondering how a Controller action can get called by a Url?

  7. nicc says:

    thanx for that very useful summary! i guess i’ll save a few hours tomorrow at work, so more time for digging deeper 🙂 i’m using jQuery now for about 8h and love it too!

    @janus: the Url.Action method is part of asp.net MVC helpers. it generates the action link for the action "LookupTags", using the controller "Utilities" ("Controller" is omitted). this is by (default) convention, since mvc uses code by convention ;).

    cheers

    nicc

  8. how to create autocomplete textbox without using ajax in asp.net.

    it should access the database to display strings to be extended in the textbox…

  9. if you use an anonimous type like this

     .Select(r => new { r.Id, t.Tag });

    and Id in an integer you’ll get a js error.

    To avoid this error use only string in the dto objects collection

    .Select(r => new { Id = r.Id.ToString(), t.Tag });

    HTH

    Claudio

  10. Jeremiah, this is an awesome post!

    I am running an issue, could you help me out with your knowledge..?

    Basically, this autocomplete extension of jQuery depends onto the ready method of the jQueryLibrary. (I am not 100% sure what it does actually, but I can guess it checks wheather the DOM has been loaded, if loaded it does something as an regular "onload" event handler).

    Now, I have an ASP.net MVC application where I am using Ajax to render a partial view (an ascx file) and that file contains the autocomplete textbox.

    As the DOM has been already loaded and I am now modified the DOM with the content of the ascx file in an Ajax fashion, my text boxes into the ascx are not doing anything autocompletion. What could be an alternate or workaround of this problem..?

    Any idea would be greatly appreciated.

    Have a nice day

  11. Harvey says:

    Hi,

    great example, I am using autocomplete for city’s which have code values. If a user enters 1 or more city ( names) and click a submit button how do I convert the city name text value in text box to the under lying city code to be sent to a service?

    regards

    Harvey

  12. Harvey says:

    Hi,

    great example, I am using autocomplete for city’s which have code values. If a user enters 1 or more city ( names) and click a submit button how do I convert the city name text value in text box to the under lying city code to be sent to a service?

    regards

    Harvey

  13. Harvey,

     Thanks for the comment.

     I believe that you are looking for the formatResult option.  More information about this can be found at the following link (under Options) http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions.

     This option allows you to format the actual input that will be sent back to the server after a selection is made.

  14. Antony says:

    what is this?What u mean by MVc

  15. VIKASH says:

    Hi,

    I have followed the same approach but it is giving me "bad request" error. Please let me know if you know the solution.

    Regards,

    Vikash

  16. Tahir Hassan says:

    Thank you, this worked perfectly for me.  Very simple to work through and implement.  

    Many Thanks,

    Tahir

  17. Pretty good post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog posts. Any way I'll be subscribing to your feed and I hope you post again soon.

  18. Junn Mendoza says:

    I have an error…

    is my Routing correct?

    routes.MapRoute(

                   "Default", // Route name

                   "{controller}/{action}/{id}", // URL with parameters

                   new { controller = "Utilitites", action = "LookupTags", id = UrlParameter.Optional } // Parameter defaults

               );

  19. Junn Mendoza says:

    Server Error in '/' Application.

    ——————————————————————————–

    The parameters dictionary contains a null entry for parameter 'limit' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult LookupTags(System.String, Int32)' in 'junnSample.Controllers.UtilititesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

    Parameter name: parameters

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

    Exception Details: System.ArgumentException: The parameters dictionary contains a null entry for parameter 'limit' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult LookupTags(System.String, Int32)' in 'junnSample.Controllers.UtilititesController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

    Parameter name: parameters

    Source Error:

  20. Junn Mendoza says:

    respelled the Utiltites – Utilities

    new { controller = "Utilities", action = "LookupTags", id = UrlParameter.Optional } // Parameter defaults

    but still received an error

  21. Junn Mendoza says:

    <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

    <!DOCTYPE html>

    <html>

    <head runat="server">

        <link href="../../Scripts/jquery-autocomplete/jquery.autocomplete.css" type="text/css" media="screen" />  

        <script type="text/javascript" src="../../Scripts/jquery-autocomplete/jquery-1.2.6.js"></script>  

        <script type="text/javascript" src="../../Scripts/jquery-autocomplete/jquery.autocomplete.js"></script>

       <script type="text/javascript">

           $(document).read(function () {

               $("#postTags").autocomplete('<%=Url.Action("LookupTags", "Utilities") %>',

               {

                   dataType: 'json',

                   pase: function (data) {

                       var rows = new Array();

                       for (var i = 0; i < data.length; i++) {

                           rows[i] = { data: data[i], value: data[i].Tag, result: data[i].Tag };

                       }

                       return rows;

                   },

                   formatItem: function (row, i, max) {

                       return row.Tag;

                   },

                   width: 300,

                   highlight: false,

                   multiple: true,

                   multipleSeparator: ","

               });

           });

       </script>

    </head>

    <body>

       <div>

          <%= Html.TextBox("postTags")  %>  

       </div>

    </body>

    </html>

  22. Junn Mendoza says:

    Typing the URL is like this – http://localhost:6223/Utilities/LookupTag/

  23. Junn,

     From the information that you posted, it looks like you are using an "int" as the parameter for the LookupTag.  

     When you use the URL of "http://localhost:6223/Utilities/LookupTag/ ", you are not passing a value for the "id" parameter.  Here are two options:

    1. You could  use an "int?" so that you can accept a null parameter (since your route has the default id parameter as an optional).

    2. You can make the route default to 0 (or some other number). (for example: new { controller = "Utilities", action = "LookupTags", id = 0} // Parameter defaults)

  24. Junn Mendoza says:

    I tried doing your sample. No error. and also no result. can you send me your sample via email. emeraldjunn@yahoo.com, please. Need the Autocomplete in my project. I done this before and its working in my Coldfusion application. Thanks A lot.

  25. RAVI says:

    GREAT Stuff about Jquery, I wanted to add autocomplete and calendar controls and I found your website very helpful. thanks a lot

    I would add the autocomplete on <a href=http://www.eddmpostcardprinting.com>EDDM Printing</a> and if there is any problem will definitely come back for help

    thanks!!!

  26. Cooper says:

    Anything after MVC 2 disables the use of :

    return Json(retValue);

    So I had to use:

    return Json(retValue, JsonRequestBehavior.AllowGet);

    Hope this helps someone.

  27. Dan says:

    Thank you for this material. Could you please provide us an example of ASP.Net MVC using jQuery autocomplete and data from a SQL database?

    Thank you

  28. Trung Nguyễn says:

    Hi everyone,

    My project not working, please help me. Thanks all

    === In Views ===

    @{

       ViewBag.Title = "LookupTags";

    }

    <link href="/Content/StyleSheet.css" rel="stylesheet" type="text/css" media="screen" />

    <script type="text/javascript" src="/Content/jquery-1.2.6.js"></script>

    <script type="text/javascript" src="/Content/jquery.autocomplete.js"></script>

    <div>

       @Html.TextBox("postTags")

    </div>

    <script type="text/javascript">

    $(document).ready(function()

    {

       $("#postTags").autocomplete('@Url.Action("LookupTags", "Utilities")',

       {

           dataType: 'json',

           parse: function(data)

           {

               var rows = new Array();

               for (var i = 0; i < data.length; i++)

                   {

                       rows[i] = { data: data[i], value: data[i].Tag, result: data[i].Tag };

                   }

               return rows;

           },

           formatItem: function(row, i, max)

           {

               return row.Tag;

           },

           width: 300,

           highlight: false,

           multiple: true,

           multipleSeparator: ","

       });

    });

    </script>

    === In controller ===

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Web;

    using System.Web.Mvc;

    namespace WebApplication1.Controllers

    {

       [HandleError]

       public class UtilitiesController : Controller

       {

           public ActionResult LookupTags(string q, int limit)

          {

              List<string> tags = new List<string>();

              tags.Add("Ronaldo");

              tags.Add("Ozil");

              tags.Add("Pepe");

              tags.Add("Dimaria");

              tags.Add("jQuery");

              tags.Add("ajax");

              var retValue = tags

                  .Where(x => x.StartsWith(q))

                  .OrderBy(x => x)

                  .Take(limit)

                  .Select(r => new { Tag = r });

              return Json(retValue);

          }

    }

    }