dotnetco.de

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

 

Leave a Comment