Simple Ajax scenario in ASP.NET MVC: filtering a table

I will present a very simple example of how to use Ajax in ASP.NET MVC. In this example we will filter a grid by making an Ajax request. Here is what the result will look like:

table

I have started by creating a new ASP.NET MVC project in Visual Studio 2015.

newproject

The first step is to add the Microsoft.jQuery.Unobstrusive.Ajax package via NuGet:

nugetajax

Once this package has been added, modify your BundleConfig.cs file located in App_Start to add the jquery.unobtrusive-ajax.js file to the jQuery bundle (or another bundle of your choice).

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
            "~/Scripts/jquery-{version}.js",
            "~/Scripts/jquery.unobtrusive-ajax.js"));

This bundle is referenced by default in the _Layout.cshtml file in the default project created by Visual Studio. If you aren’t using this default project template, add the bundle to your layout or your page.

Next I create two model classes in the project:

namespace Ajax2.Models
{
    public class DepartmentModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
using System.Collections.Generic;

namespace Ajax2.Models
{
    public class DepartmentsModel
    {
        public bool Filtered { get; set; }
        public IEnumerable<DepartmentModel> Departments { get; set; }

        public DepartmentsModel()
        {
            Departments = new List<DepartmentModel>();
        }
    }
}

DepartmentModel is the model that will be used for each line of the table. DepartmentsModel will be our view model for our page. In this view model we have a collection of all our departments to be displayed in our table and whether we apply some filtering.

Create or modify a view (I modified the Index of the Home controller) likewise:

@model Ajax2.Models.DepartmentsModel

@{
    ViewBag.Title = "Home Page";
}

<br />

@using (Ajax.BeginForm("FilterDepartmentsAjax",
                   new AjaxOptions
                   {
                       HttpMethod = "POST",
                       InsertionMode = InsertionMode.Replace,
                       UpdateTargetId = "department-table"
                   }))
{
    <label>Filter: </label>
    @Html.CheckBoxFor(model => model.Filtered)
    <input type="submit" value="Submit" />
}

<div id="department-table">
    @{ Html.RenderPartial("DepartmentsTablePartial", 
                          Model); }    
</div>

The first thing to note is we are using the AjaxHelper. Alternatively we could write JavaScript code ourselves, the AjaxHelper is just a convenience. When choosing to write the JavaScript code ourselves, we must use jQuery which is what the helper is using.

The important bits is that we want to replace an element identified by the id department-table.

When we call this form, the contents returned by the Ajax action on the controller will replace the contents of the div. We will replace the div’s content with a partial view, so we might as well reference it right now.

Note that it is possible not to render the partial view before making the first Ajax call which can make sense in some scenarios.

The partial view is nothing special:

@model Ajax2.Models.DepartmentsModel

<table class="table table-striped">
    <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
        </tr>
    </thead>

    <tbody>
        @foreach (var department in Model.Departments)
            {
            <tr>
                <td>@department.Id</td>
                <td>@department.Name</td>
            </tr>
        }
    </tbody>
</table>

Note that it contains the same model as it’s parent view. This is convenient in our scenario, but a different model could be used instead.

Now for the controller:

using Ajax2.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace Ajax2.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var model = new DepartmentsModel
            {
                Filtered = true,
                Departments = GetDepartments(filtered: true),
            };

            return View(model);
        }

        [HttpPost]
        public PartialViewResult FilterDepartmentsAjax(DepartmentsModel model)
        {
            var updatedModel = new DepartmentsModel
            {
                Filtered = model.Filtered,
                Departments = GetDepartments(filtered: model.Filtered),
            };

            return PartialView("DepartmentsTablePartial", 
                               updatedModel);
        }

        private IEnumerable<DepartmentModel> GetDepartments(bool filtered)
        {
            var departments = new List<DepartmentModel>
            {
                new DepartmentModel { Id = 1, 
                                      Name = "Sales" },
                new DepartmentModel { Id = 2, 
                                      Name = "Accounting" },
                new DepartmentModel { Id = 3, 
                                      Name = "Marketing" },
                new DepartmentModel { Id = 4, 
                                      Name = "HR" },
                new DepartmentModel { Id = 5, 
                                      Name = "IT" },
                new DepartmentModel { Id = 6, 
                                      Name = "Customer S." },
            };

            if (filtered)
                return departments.Where(x => x.Id < 4);

            return departments;
        }
    }
}

GetDepartments is meant to be a placeholder. Normally in a real application we would get the data from a data source or a service.

Our FilterDepartmentsAjax must be decorated with the [HttpPost] attribute, return a PartialViewResult and use a return statement that returns a return PartialView rather than a view.

A UI improvement

Rather than have a submit button, it would be better to have the table update when the user check’s the filter checkbox.

Normally we could have just called this.form.submit() on the checkbox likewise

@Html.CheckBoxFor(model => model.Filtered, 
                  new { onclick = "this.form.submit();" })

but sadly this doesn’t work with Ajax. Courtesy of this stackoverflow answer we can submit it likewise:

@Html.CheckBoxFor(model => model.Filtered, 
                  new { 
                     onclick = "$(this).parents('form:first')
                                       .find(':submit')[0]
                                       .click();" 
                  })

And then hiding the existing input element (which must remain on the page).

Conclusion

I have posted the code on GitHub and you can find it here.

4 thoughts on “Simple Ajax scenario in ASP.NET MVC: filtering a table

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s