Unobtrusive AJAX
Unobtrusive AJAX is an approach in which the AJAX behaviors are separated out from the HTML elements. ASP.NET MVC framework provides supports for AJAX
using the AjaxHelper and AjaxHelperExtensions classes. For example you can easily create an HTML form that submits the data through AJAX using the
BeginForm extension method. The below listing shows how to create an AJAX form in a Razor view.
@Ajax.BeginForm("AddMovie", new AjaxOptions {
UpdateTargetId = "divMovies"
})
Listing 1. Creating an AJAX form in razor
In views we can access the AjaxHelper through the property AJAX. Prior to version 3, MVC framework doesn't
supports unobtrusive AJAX so when you try to create an AJAX form using the above code you will see the following html rendered to the browser.
<form action="/Movie/AddMovie" id="form0" method="post"
onclick="Sys.Mvc.AsyncForm.handleClick(this, new Sys.UI.DomEvent(event));"
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event),
{ insertionMode: Sys.Mvc.InsertionMode.replace, updateTargetId: 'divMovies' });">
Listing 2. Obtrusive html generated by the AJAX form
You can notice the event handlers are directly specified in the html, also the arguments are passed as an object to the
onsubmit handler.
Yeah, the HTML looks ugly! The unobtrusive AJAX helps to clean away the mess by separating the AJAX behaviors from the DOM.
Using unobtrusive AJAX we not only gain clean html but also we can gracefully handle the cases where the browsers doesn't supports
JavaScript.
ASP.NET MVC 3 supports unobtrusive AJAX with the help of jQuery.
When unobtrusive AJAX enabled this is what the form looks like:
<form action="/Movie/AddMovie"
data-ajax="true"
data-ajax-mode="replace"
data-ajax-update="#divMovies"
id="form0" method="post">
Listing 3. Unobtrusive html generated by MVC 3
It's clearly evident the html is clean and easy to maintain.
How thing works?
The MVC framework represents the additional arguments that need to be passed for AJAX calls as HTML5 data attributes in the form. Microsoft provides
a library called jquery.unobtrusive-ajax.js that reads form elements those have the attribute data-ajax as true, extract the data attributes
attached to the form and call the necessary jQuery's AJAX methods passing those arguments.
In MVC, to enable unobtrusive AJAX we have to do couple of things.
- Include both the jQuery library and Microsoft's unobtrusive AJAX library in views.
- Set the
UnobtrusiveJavaScriptEnabled as true in web.config.
Creating a custom AJAX helper extension
The MVC 3 framework supports AJAX behaviors for two html elements: forms and links. You can create an AJAX form or an AJAX link by the
AjaxHelper class.
To create an AJAX form or an AJAX link we need to supply the AjaxOptions instance to the extension method. The MVC framework writes the properties specified
in the AjaxOptions instance as data attributes to the html elements.
Here is an example of creating an AJAX link using one of the extension method provided by the
AjaxHelper.
@Ajax.ActionLink("Load All Movies", new AjaxOptions {
UpdateTargetId = "divMovies",
InsertionMode = InsertionMode.Replace
})
Listing 4. AJAX link
Like custom html helpers we can create custom AJAX helpers. The approach is nearly same as creating a custom html helper, instead of creating
extension method for the HtmlHelper class we have to do for AjaxHelper.
Let see how we can create an AJAX search textbox by creating a custom AJAX helper. Our search textbox make AJAX calls to the server when we enter/change
the text and dynamically update the html. First we have to create an extension method for
AjaxHelper as shown in the below listing.
public static MvcHtmlString Textbox(this AjaxHelper ajaxHelper, string name,
AjaxOptions ajaxOptions, object htmlAttributes)
{
var tag = new TagBuilder("input");
tag.MergeAttribute("name", name);
tag.MergeAttribute("type", "text");
tag.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
tag.MergeAttributes((ajaxOptions ?? new AjaxOptions()).ToUnobtrusiveHtmlAttributes());
return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}
Listing 5. Custom textbox AJAX helper
Our extension method Textbox is quite simple takes three parameters: a name for the textbox,
AjaxOptions instance and htmlattributes object.
In the first three lines of the code we are creating the input element with appending the name and type attributes using the
TagBuilder class.
Then we are appending the additional html attributes passed as an anonymous object
htmlattributes to the input element by calling the AnonymousObjectToHtmlAttributes method of HtmlHelper class.
What we are doing next is quite important, we are converting the passed AjaxOptions instance into HTML5 data attributes and appending to the input element by
calling the AnonymousObjectToHtmlAttributes method of it.
So our search textbox is quite good but not ready to use. Unless we do some work in the client-side it simply doesn't work.
Extending the unobtrusive JavaScript library
The unobtrusive JavaScript library queries only for form and anchor elements and not for others unless we do something about that.
To enable AJAX behaviors for textbox we have to modify the library.
$("input[type=text][data-ajax=true]").live("keyup", function (evt) {
asyncRequest(this,
{
type: "GET",
data: [{ name: $(this).attr(�name'), value: $(this).val()}]
});
});
Listing 6. Modifying unobtrusive AJAX library for textbox helper
In the above script we query the textboxes that have AJAX enabled and listen to the keyup event. Whenever the event fires we make an AJAX call
using the private helper method asyncRequest. We have to add this snippet right before or above the library queries for form and link elements.
Test drive
We can call for custom AJAX helper as below from any razor view, we have to include the namespace where our extension lives in the
web.config under the Views folder.
@Ajax.Textbox("search",
new AjaxOptions
{
Url = "/Movie/Search",
UpdateTargetId = "movies",
InsertionMode = InsertionMode.Replace
},
new { size = 50 })
Listing 7. Creating custom AJAX textbox helper in razor view
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory,
System.Web.Mvc, Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="TextboxAjaxHelper.Extensions" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
Listing 8. Adding the extension namespace in web.config
Here is a sample application that describes
how we can use our custom AJAX helper.
Summary
In this article we saw about unobtrusive AJAX and how we can create custom AJAX helpers quite easily by adding extension methods to the
AjaxHelper class.
I'm a software developer from south tip of India. I spent most of the time in learning new technologies. I've a keen interest in client-side technologies especially JavaScript and admire it is the most beautiful language ever seen.
I like sharing my knowledge and written some non-popular articles. I believe in quality and standards but blames myself for lagging them.
I believe in small things and they makes me happy!