Another JQuery Autocomplete Example With ASP.NET Webforms

This is a quick run through of how to implement a jQuery autocomplete with webforms. The lookup data consists of about 600 items and changes very rarely so I want to load the data only once when the page loads rather than sending a query to the database as the user types in the input box.

On the Webform is a input box which will have autocomplete feature.

<div>
    <asp:Label ID="Label5" runat="server" Text="Depot Code:" AssociatedControlID="txtDepotCode" />
    <asp:TextBox ID="txtDepotCode" runat="server" ClientIDMode="Static" TabIndex="5" />
    <asp:TextBox ID="txtDepotName" runat="server" ClientIDMode="Static" TabIndex="6" />
</div>

In this javascript code a webservice is being called to retrieve the items via an ajax call. When the data is returned it is set as the source data for the autocomplete input box.

$(function () {
    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "creditqueryservice.asmx/GetDepots",
        dataType: "json"
    }).done(function (response) {
        var data = $.map(response.d, function (item) {
            return {
                value: item.DepotCode,
                label: item.DepotCode + ' - ' + item.DepotName
            };
        });

        $("#txtDepotCode").autocomplete({
            source: data,
            minLength: 2,
            select: function(event, ui) { 
                // do something here.  ui parameter holds the values of the item selected
                $("#" + this.id).val(ui.item.value);
                $("#" + this.id + "name").val(ui.item.DepotName);
                return false;
            }
        });
    });
});

The depots are retrieved via a repository (_branchesRepo) variable in the class. Retrieve the data suitable to your application.

[WebMethod]
public List<Depot> GetDepots()
{
    var depots = new List<Depot>();
     if (depots == null || depots.Count == 0)
    {
        depots = _branchesRepo.GetBranches();
    }
    return depots;
}

To validate what the user has entered the autocomplete data can retrieved as in the code below.

var source = $("#txtDepotCode").autocomplete("option", "source");

Now you can compare the value entered with the values in the list. You would really only do this if the user typed into the input box without selecting an item from the matched list.

Validate at least one option is selected in radio button list on Webform

On a webform there is a radiobutton list. The user must select at least one of the options for the form to be valid.

<div>
	<asp:Label ID="Label37" runat="server" Text="Is Sales Item:" AssociatedControlID="rblSaleItem" />
	<asp:RadioButtonList ID="rblSaleItem" runat="server" ClientIDMode="Static" TabIndex="36"
		RepeatDirection="Horizontal" RepeatLayout="Flow" CssClass="checkbox-list">
		<asp:ListItem Text="Yes" Value="1"></asp:ListItem>
		<asp:ListItem Text="No" Value="0"></asp:ListItem>
	</asp:RadioButtonList>
	<asp:CustomValidator ID="IsSaleItemCustomValidator" runat="server" Text="Is Sales Item: selection is required"
		Display="Dynamic" ClientIDMode="Static" ClientValidationFunction="IsSalesItemValidator"
		OnServerValidate="IsSalesItemValidation" ValidationGroup="FORMGROUP" CssClass="field-validation-error"></asp:CustomValidator>
</div>

Here we have the javascript validation. The radiobutton list and validator are in the same div element, so from the validation control triggered we go up to the parent to find the radiobutton list. Each radio button in the list is tested to see if it is selected.

// Javascript client side validation
function IsSalesItemValidator(sender, args) {
    args.IsValid = false;

    $("#" + sender.id).parent().find(".checkbox-list").find(":radio").each(function () {
        if ($(this).is(":checked")) {
            args.IsValid = true;
            return;
        }
    });
}

On the server side the validation works in a similar way.

// C# Server side validation
protected void IsSalesItemValidation(object source, ServerValidateEventArgs args)
{
    // has a sale item check box been selected
    foreach (ListItem li in rblSaleItem.Items)
    {
        if (li.Selected)
        {
            args.IsValid = true;
            break;
        }
    }
}

I actually do not like the idea of iterating through the radiobutton list to find if one is checked. Normally the radiobutton lists are quite short on a page so it is probably not a big overhead, but it is too old school lazy coding for my liking. In .Net3.5 the Enumerable class was introduced in the System.Linq namespace. Unsing the Enumerable.Cast method we can construct linq queries to retrieve the selected item from the radiobutton list instead of iterating all the items.

protected void IsSalesItemValidation(object source, ServerValidateEventArgs args)
{
    var selectedItem = (from li in rblSaleItem.Items.Cast<ListItem>()
                        where li.Selected == true
                        select li).FirstOrDefault();
    /*
    // Alternatively if you prefer inline linq
    var selectedItem = rblSaleItem.Items.Cast<ListItem>()
                        .Where(item => item.Selected == true).FirstOrDefault();
    */
    
    args.IsValid = SelectedItem != null && SelectedItem.Selected;
}

Using the FirstOrDefault() method will return null if there are not selected items in the radiobutton list. If we were to use the First() method an InvalidOperationException would be thrown if there are no elements that meet the query conditions.
It is safe to use the Cast method in this situation because it is guaranteed all the items in the collection are of the ListItem type. If the Cast method was used on a collection containing different objects an InvalidCastException will be thrown. If the collection object itself is null an ArgumentNullException will be thrown.

JQuery Autocomplete Example With ASP.NET Webforms

This will be a quick run through of how I implemented autocomplete in a Webforms application.

The data for the autocomplete list is represented in a class.

public class Depot
{
    public string DepotCode { get; set; }
    public string DepotName { get; set; }
}

A WebMethod in a service class is called to retrieve the list. I am keeping the amount of the data small for brevity. In this simple example I am checking what the search term starts with and populating a list with similar values. In a real situation the list being returned from this WebMethod would be generated from a search in a database.

[WebMethod]
public List<Depot> GetDepots(string search)
{
    if (search.StartsWith("11"))
    {
        return new List<Depot>{ 
            new Depot{DepotCode= "1111",DepotName= "London"},
            new Depot{DepotCode= "1122",DepotName= "Birmingham"}
        };
    }
    else
    {
        return new List<Depot>{ 
            new Depot{DepotCode= "0111",DepotName= "London"},
            new Depot{DepotCode= "0122",DepotName= "Birmingham"}
        };
    }
}

This javascript is the magic. The request parameter of the source function contains the search text, in this case the text I enter into the input box. I have set minLength to 2, so 2 characters must be entered for the autocomplete list to appear.

In the success function each item of data is transposed into an object consisting of a value and label property. The label property is the text displayed in the autocomplete list.  When an item in the list is selected the Value property is the text that populates the input box.

$("#txtDepotCode").autocomplete({
    source: function (request, response) {
        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            url: "creditqueryservice.asmx/GetDepots",
            data: "{'search':'" + request.term + "'}",
            dataType: "json",
            success: function (data) {
                response($.map(data.d, function (item) {
                    return {
                        value: item.DepotCode,
                        label: item.DepotCode +' - '+ item.DepotName
                    };
                }));
            },
            error: function (result) {
                alert("Error");
            }
        });
    },
    minLength: 2
});

There could potentially be any number of issues but I got this issue

object doesn't support property or method 'curCSS'

which turned out to be a mismatch between the version of jQuery and the version of jQueryUI. After changing the version of jQueryUI this issue went away.

How to update partial view using jquery ajax

I wanted to give a quick but clear example how to use jQuery to update a partial view, an example which could be easy to replicate.

We need a model
The model consists of product class with three properties; a product code, name and price.

public class Product
{
    [Required]
    public string Code { get; set; }
    [Required]
    public string Name { get; set; }
    [Required]
    [DataType(DataType.Currency)]
    public decimal UnitPrice { get; set; }
}

And a Controller
For simplicity there is no specific data layer or repository, the controller contains a global array of products. When a http post is made to the GetProducts ActionResult a parameter is passed specifying how many products to return.

public class HomeController : Controller
{
    private List<Product> products = new List<Product>() ;

    public HomeController()
    {
        products.Add(new Product { Code = "P001", Name = "Hair Dryer", UnitPrice = 10.50M });
        products.Add(new Product { Code = "P002", Name = "Carpet Cleaner", UnitPrice = 3.60M });
        products.Add(new Product { Code = "P003", Name = "Hair Remover", UnitPrice = 12.10M });
        products.Add(new Product { Code = "P004", Name = "Vacuum Cleaner", UnitPrice = 80.99M });
        products.Add(new Product { Code = "P005", Name = "Table", UnitPrice = 7.69M });
        products.Add(new Product { Code = "P006", Name = "Duvet Cover", UnitPrice = 12.89M });
        products.Add(new Product { Code = "P007", Name = "Towel", UnitPrice = 3.50M });
        products.Add(new Product { Code = "P008", Name = "Electric Oven", UnitPrice = 125.99M });
        products.Add(new Product { Code = "P009", Name = "Hair Straighteners", UnitPrice = 8.90M });
        products.Add(new Product { Code = "P010", Name = "Belt", UnitPrice = 3.50M });
    }

    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult GetProducts(int quantity)
    {
        var selectedProducts = products.Take(quantity);
        return PartialView("_ProductList", selectedProducts);
    }
}

The Main View
mvcpartialviewupdate-main-view
Selecting from the dropdown list causes a change event the initiates the post to the server. If the post is successful the partial view is updated.
The date and time is displayed for comparison with the date and time on the partial view, they will be different.

<h2>Product Display</h2>
<div class="col-sm-6">
    @DateTime.Now.ToLongDateString()
    @DateTime.Now.ToLongTimeString()
<div class="panel panel-default">
<div class="panel-heading">
            Products</div>
<div class="panel-body">
<div class="form-group form-group-sm">
                <label class="control-label" for="PageSize">
                    How many products should be displayed?
                </label>
<div>
                    <select id="PageSize">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select></div>
</div>
<div id="SelectedProducts"></div>
</div>
</div>
</div>

jQuery AJAX
When a selection is made from the dropdown list the change event is triggered and a POST made to the server.

@section scripts{
    <script type="text/javascript">

        $(document).ready(function () {

            $("#PageSize").on("change", function () {
                var val = $('#PageSize').val();
                $.ajax({
                    url: "/Home/GetProducts",
                    type: "POST",
                    data: { quantity: val }
                })
                .done(function (partialView) {
                    $("#SelectedProducts").html(partialView);
                });
            });
        });
    </script>
}

And the Partial View (_ProductList.cshtml)
The partial view displays a list of products in a table. The POST date and time is displayed for comparison purposes.

@model IEnumerable<MVCUpdatePartial.Models.Product>
<div class="editor-label">
    Selected Products</div>
<table class="table">
    @foreach(var product in Model)
    {
<tr>
<td>@product.Code</td>
<td>@product.Name</td>
<td>@product.UnitPrice</td>
</tr>
}</table>
Updated: @DateTime.Now.ToLongDateString()
@DateTime.Now.ToLongTimeString()

After the POST
And how the view looks after the POST and the partial view is updated.
mvcpartialviewupdate-main-view-after-post

Javascript IntelliSense in Visual Studio

IntelleSense is a pretty standard feature of any modern Integrated Development Environment (IDE). Visual Studio has the ability to display IntelleSense not only for the whole .Net framework but also for any libraries included in the solution and any custom code written in C#, VB or similar language. IntelliSense is not available for javascript files by default, partly because javascript is not build by a compiler. Fortunately it is quite easy to configure.
Firstly, create a new file called _references.js in the ‘Script’ folder of your project (note the intended leading underscore). Then add a reference for each file you require IntelliSense for like below;

/// <reference path="jquery-2.1.1.js" />
/// <reference path="knockout-3.2.0.debug.js" />
/// <reference path="your-custom-file.js" />

There is a shortcut to typing the references manually, simply drag and drop the file from the Solution Explorer into the editor pane and the reference will be added for you.

That’s basically it. Simple but useful.