Autocomplete in asp.net with images and formatting
Before jQuery, I used AJAX Control Toolkit and I liked it as it contained lots of helpful widgets. With jQuery there are now much more options how to implement something. Today I searched for something like the autocomplete so you could type in the first letters and then get some proposals. We all know this from Google etc. Some sides also have formatting in the result list, e.g. at Telerik, or also show images. So let’s see whether we could do the same for asp.net.
Requirements
In most of my projects I use jQuery, jQueryUI and Bootstrap. Maybe we could build it with just these 3 scripts. jQueryUI has an autocomplete option. This might be a good start.
jQuery Data Retrieval
Data Retrieval is of course done via a Webservice which is explained below. When data is returned, the content is copied into internal variables so we could use them later on when we setup the display format. As in previous example I used Name, ID, Additional Info and Image but of course you are free to add whatever you want. Don’t forget to update the function in the success-section of the Ajax-Script.
Styling
For the formatting we use the autocomplete-option as explained in jQueryUI custom data example . Additionally I’ve added some very basic CSS formatting using the classes username, userimage and userinfo just to show how it works. The rest is formatted by jQueryUI and Bootstrap.
Store user selection
Once we select a name, we want to display the username in the textbox but also keep the unique ID for later processing because e.g. a username might exist twice but the ID is unique. Therefore the select-event not just updates the textbox but it also stores the userid in our hidden field SelectedUserID.
Webservice Data Retrieval
The data retrieval in the example is very easy: I hardcoded a table with some usernames. In the live project we have some database where the data is retrieved on the fly but for this example I kept it as simple as possible. So we have a select-statement which uses the supplied user input. A new instance of class UserDetails is created and filled with the returned data. If you want to restrict the maximum number of return results you should filter using LINQ or a statement (SELECT TOP 2 …) accordingly. Additionally there are several ways of providing the JSON result. I’ve decided to use a dedicated class as this might be easier to understand. Of course you are free to use other methods.
The Code
As usual here is the full source code so you could easily build it on your own.
Autocomplete.aspx
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="AutoComplete.aspx.vb" Inherits="WebApplication1.AutoComplete" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <script src="//code.jquery.com/jquery-1.11.0.min.js" type="text/javascript"></script> <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"> <title></title> <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js" type="text/javascript"></script> <link href="https://code.jquery.com/ui/1.11.4/themes/start/jquery-ui.css" rel="Stylesheet" type="text/css" /> <style> .username { display: block; font-weight: bold; margin-bottom: 1em; } .userimage { float: left; max-height: 50px; max-width: 50px; margin-right:10px; } .userinfo { margin: 0; padding: 0; } </style> <script type="text/javascript"> $(document).ready(function () { $("#<%=SelectedUsername.ClientID %>").autocomplete({ source: function (request, response) { $.ajax({ url: '<%=ResolveUrl("~/Webservices/WebService1.asmx/GetUsers") %>', data: "{ 'input': '" + request.term + "'}", dataType: "json", type: "POST", contentType: "application/json; charset=utf-8", success: function (data) { response($.map(data.d, function (item) { return { username: item.Username, userid: item.UserID, info: item.AdditionalInfo, image: item.ImageURL } })) } }); }, minLength: 1, select: function (event, ui) { $("#<%=SelectedUsername.ClientID %>").val(ui.item.username); $("#<%=SelectedUserID.ClientID %>").val(ui.item.userid); return false; } }) .autocomplete("instance")._renderItem = function (ul, item) { return $("<li>") .append("<a><img class='userimage' src='" + item.image + "' class='img-rounded' />") .append("<p class='username'>" + item.username + "</p>") .append("<p class='userinfo'>" + item.info + "</p></a>") .appendTo(ul); }; }); </script> </head> <body> <form id="form1" runat="server"> <div style="margin: 100px"> <asp:TextBox ID="SelectedUsername" runat="server"></asp:TextBox> <asp:HiddenField ID="SelectedUserId" runat="server" /> <asp:Button ID="Process" runat="server" Text="Do whatever" /> </div> </form> </body> </html>
Autocomplete.aspx.vb
Public Class AutoComplete Inherits System.Web.UI.Page Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load End Sub Private Sub btnSubmit_Click(sender As Object, e As System.EventArgs) Handles Process.Click Dim selectedName As String = SelectedUsername.Text Dim selectedID As String = SelectedUserId.Value End Sub End Class
Webservice1.asmx.vb
Imports System.Web.Services Imports System.Web.Services.Protocols Imports System.ComponentModel ' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. <System.Web.Script.Services.ScriptService()> _ <System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _ <System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _ <ToolboxItem(False)> _ Public Class WebService1 Inherits System.Web.Services.WebService Public Class UserDetails Public Username As String Public UserID As String Public ImageURL As String Public AdditionalInfo As String End Class <WebMethod()> _ <Script.Services.ScriptMethod(ResponseFormat:=Script.Services.ResponseFormat.Json)> _ Public Function GetUsers(ByVal input As String) As List(Of UserDetails) Dim dt As DataTable = CreateDatatable() Dim rows As DataRow() rows = dt.Select(String.Format("Username like '%{0}%'", input)) Dim result As New List(Of UserDetails) For Each row In rows Dim r As New UserDetails r.Username = row("Username") r.UserID = row("UserID") r.ImageURL = row("ImageURL") r.AdditionalInfo = row("AdditionalInfo") result.Add(r) Next Return result End Function Private Function CreateDatatable() As DataTable Dim dt As New DataTable dt.Columns.Add("UserID") dt.Columns.Add("Username") dt.Columns.Add("ImageURL") dt.Columns.Add("AdditionalInfo") Dim row As DataRow row = dt.NewRow row("UserID") = "ZuckerbergM" row("Username") = "Mark Zuckerberg" row("ImageURL") = "https://upload.wikimedia.org/wikipedia/commons/3/31/Mark_Zuckerberg_at_the_37th_G8_Summit_in_Deauville_018_v1.jpg" row("AdditionalInfo") = "Co-Founder of Facebook" dt.Rows.Add(row) row = dt.NewRow row("UserID") = "MuskE" row("Username") = "Elon Musk" row("ImageURL") = "https://upload.wikimedia.org/wikipedia/commons/0/04/Elon_Musk_-_The_Summit_2013.jpg" row("AdditionalInfo") = "CEO of SpaceX and Tesla Motors" dt.Rows.Add(row) row = dt.NewRow row("UserID") = "GatesB" row("Username") = "Bill Gates" row("ImageURL") = "https://upload.wikimedia.org/wikipedia/commons/0/01/Bill_Gates_July_2014.jpg" row("AdditionalInfo") = "Co-Founder of Microsoft" dt.Rows.Add(row) row = dt.NewRow row("UserID") = "DorseyJ" row("Username") = "Jack Dorsay" row("ImageURL") = "https://upload.wikimedia.org/wikipedia/commons/6/68/Jack_Dorsey_2012_Shankbone.JPG" row("AdditionalInfo") = "Co-Founder of Twitter" dt.Rows.Add(row) Return dt End Function End Class
Such a nice post on Rich text editor JavaScript, thanks for sharing.