• Tags with autocomplete in asp.net textbox

    My last posting showed how to use jQueryUI autocomplete with some individual formatting and an image. Now I have a similar request: I want to build an input for tags (or tokens). It should also provide suggestions from a backend using autocomplete (so that’s similar to previous posting) but the returned list does not need any special formatting or images. Instead I need to have an option to allow multivalue, and it would be nice to have some box around each tag and an ‘x’ to delete a tag.

    Requirements

    In most of my projects I still use jQuery, jQueryUI and Bootstrap. jQueryUI has already an autocomplete option which allows multi-value input, but the design is not too nice. After some search I found Bootstrap-Tokenfield from Sliptree. It uses jQueryUI autocomplete (or Twitter Typeahead if you like) which has several advantages as it does not reinvent the wheel but uses an existing robust script, and I could reuse my existing autocomplete options and webservice without too many changes :-). Additionally it integrates into Bootstrap design, and further more provides additional options like copy-and-paste.

    Bootstrap Tokenfield Configuration

    You only need to do 2 things: Inform the tokenfield script to take care of your textbox, and supply information how to get the autocomplete options. The first one is simply done by calling MyTextbox.tokenfield. Then include the autocomplete options there (see below).

    Webservice Data Retrieval

    The data retrieval in the example is very easy: I hardcoded a table with some usernames (reused from my previous posting). 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. If you want to restrict the maximum number of return results you should filter using LINQ or a statement (SELECT TOP 2 …) accordingly. All the data is then placed into a string array and returned to the script. You don’t need to take care about JSON or else.

     

     

    Get the input

    To get the input you could as usual just get the Text of the Textbox as this contains all selected tags separated by comma.

     

    The Code

    As usual here is the full source code so you could easily build it on your own.

     

     Tokenfield.aspx

    <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="TokenField.aspx.vb" Inherits="WebApplication1.TokenField" %>
     
    <!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">
        <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" />
            <script src="js/bootstrap-tokenfield.js" type="text/javascript"></script>
        <link href="css/bootstrap-tokenfield.css" rel="Stylesheet" type="text/css" />
        <title>TokenField</title>
        <script type="text/javascript">
            $(document).ready(function () {
                $("#<%=MyInput.ClientID %>").tokenfield({
                    autocomplete: {
                        source: function (request, response) {
                            $.ajax({
                                url: '<%=ResolveUrl("~/Webservices/WebService1.asmx/GetNames") %>',
                                data: "{ 'input': '" + request.term + "'}",
                                dataType: "json",
                                type: "POST",
                                contentType: "application/json; charset=utf-8",
                                success: function (data) {
                                    response(data.d)
                                }
                            });
                        },
                        delay: 100
                    }
                })
            });
        </script>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <div style="margin: 100px">
                <asp:TextBox ID="MyInput" runat="server"></asp:TextBox>
                <asp:Button ID="DoSomething" runat="server" Text="DoSomething" />
            </div>
        </div>
        </form>
    </body>
    </html>

     

    Tokenfield.aspx.vb

    Public Class TokenField
        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 DoSomething_Click(sender As Object, e As System.EventArgs) Handles DoSomething.Click
            Dim test As String = MyInput.Text
     
        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
     
        <WebMethod()> _
      <Script.Services.ScriptMethod(ResponseFormat:=Script.Services.ResponseFormat.Json)> _
        Public Function GetNames(ByVal input As String) As String()
            Dim dt As DataTable = CreateDatatable()
            Dim rows As DataRow()
            rows = dt.Select(String.Format("Username like '%{0}%'", input))
            Dim result(rows.Length - 1) As String
            For i As Integer = 0 To rows.Length - 1
                result(i) = rows(i).Item("Username").ToString
            Next
            Return result
        End Function
     
        Private Function CreateDatatable() As DataTable
            Dim dt As New DataTable
            dt.Columns.Add("Username")
     
            Dim row As DataRow
            row = dt.NewRow
            row("Username") = "Mark Zuckerberg"
            dt.Rows.Add(row)
     
            row = dt.NewRow
            row("Username") = "Elon Musk"
            dt.Rows.Add(row)
     
            row = dt.NewRow
            row("Username") = "Bill Gates"
            dt.Rows.Add(row)
     
            row = dt.NewRow
            row("Username") = "Jack Dorsay"
            dt.Rows.Add(row)
     
            Return dt
     
        End Function
    End Class

     

Leave a comment

If you want to share your opinion, leave a comment.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

  • Beryl Small says:Reply
    August 9, 2017 at 14:43

    I cannot get this to work. What do you mean by “calling MyTextbox.tokenfield”? I do not see how or where the tokenfield is told to handle the textbox accept for the JQuery that makes the Ajax call. I need this functionality so if you can expound on your code above, it would be greatly appreciated.

    • Kai Wilzer says:Reply
      August 9, 2017 at 15:44

      Hi Beryl,
      have a look at line 16 of Tokenfield.aspx. You only need to define that this textbox is a tokenfield, and the implemented jQuery script will do the rest.
      Hope this helps!
      Kai

  • MohmdNader says:Reply
    October 22, 2017 at 10:56

    Thank U … can you write in c# lang plz.

    • Kai Wilzer says:Reply
      October 22, 2017 at 10:58

      You could use a converter like http://converter.telerik.com/ to transfer from vb.net to c#.

      • MohmdNader says:Reply
        October 22, 2017 at 11:31

        Thanks Again

  • Ahmad says:Reply
    December 12, 2017 at 10:23

    Code works perfectly, I just wonder what if I want to prevent duplicates? I mean if one tag is already chosen, it won’t show in the suggestions??

    Also, is it possible to get each tag ID? like two parameters behind each tag Text, and Value?

    Thanks!

    • Kai Wilzer says:Reply
      December 12, 2017 at 10:28

      Hi Ahmad,
      regarding duplicates: the webservice is triggered with every new character so of course you could add a check there and only return a list with tags not chosen yet.
      regarding IDs: the tags should of course be unique, so that’s already some kind of ID. Technically it would not be necessary to have an additional unique ID as long as the tags are unique. When you further process the input you could of course merge the tags with your ID table.
      Hope this helps!