Ajax improvements in MVC 3

This post is part of the series I’m doing on the newly released ASP.NET MVC 3.

The official tagline is that ASP.NET MVC 3 enables richer JavaScript scenarios and takes advantage of emerging HTML5 capabilities.  Sounds good, but what improvements have actually been made?  Let’s take a look.

How is it used

I have always felt the MVC Ajax helpers were lacking – I pretty much always write the Ajax calls by hand using jQuery.  Let’s take a look at an example using Ajax.

<% using(Ajax.BeginForm("Login", "Account",
       new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "LoginDiv" })) { %>

<div id="LoginDiv">

    <p>
    <label for="username">Username</label>
    <input type="text" name="username" />
    </p>

    <p>
    <label for="username">Password</label>
    <input type="password" name="password" />
    </p>

    <input type="submit" value="Login" />

</div>

<% } %>

On the server I have created the following action.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Login(LoginViewModel loginViewModel)
{
    return PartialView("LoggedIn");
}

My partial view simply displays a success message.

LoginSuccess

This works in both MVC 2 and MVC 3.  So what’s the big deal?

How to do this in MVC 2

The difference is in the generated JavaScript and includes.  In MVC 2 we need the following includes.

<script src="<%=Url.Content("~/Scripts/MicrosoftAjax.js") %>" type="text/javascript"></script>
<script src="<%=Url.Content("~/Scripts/MicrosoftMvcAjax.js") %>" type="text/javascript"></script>

Let’s take a look at the generated JavaScript.

<form action="/Account/Login" 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,
            httpMethod: "POST",
            updateTargetId: "LoginDiv" });">

This works, but it’s rather messy.  For one thing, we need to use the Microsoft Ajax libraries instead of the common jQuery ones, and the generated code does not follow the principle of Unobtrusive JavaScript.

Now let’s take a look at the same scenario in MVC 3.  We still need an include, but it’s the jQuery version.

<script src="@Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

Now the same code generates very nice markup.

<form action="/Account/Login" data-ajax="true" data-ajax-method="POST" data-ajax-mode="replace"
    data-ajax-update="#LoginDiv" id="form0" method="post">

Which is much neater.  What about ActionLinks?  (I’m using Razor as the View Engine)

@Ajax.ActionLink("Home", "PlanetList", "Planet",
    new AjaxOptions() { InsertionMode = InsertionMode.Replace, UpdateTargetId = "LoginDiv" })

This generates the following markup.

<a data-ajax="true" data-ajax-mode="replace" data-ajax-update="#LoginDiv" href="/Planet/PlanetList">Planets</a>

Very cool.

Further Reading

Again, MVC 3 has only recently been released so there is very little information available.  The only similar post I found was by Jeremy Skinner.

Happy coding.