Simple AJAX ASP.NET MVC web-pages that work without JavaScript

AJAX, .NET 4, MVC etc… work together to make web-development very simple, and when Microsoft introduced @Ajax.BeginForm(…) it looked as though life couldn’t get any easier. However, now that jQuery is integrated into Visual Studio as well, I think there are better ways of building AJAX enabled web-pages that using Microsoft’s take on AJAX.

In this post I’ll be building an example solution that is AJAX enabled using jQuery, but works fine if the user has JavaScript switched off. (Although I’m not sure how many people that is this days. In 2010 some say it was around 2% of users but probably less now, although there are still going to be users with a valid reason why they need to keep it disabled.)

So, the final solution is going to look like this:

Simple Ajax 1

I started with an empty MVC 4 project in Visual Studio 2010 and added references to jQuery using the awesome NuGet.

IndexViewModel in the AjaxTest.Models.Home namespace looks like this:

namespace AjaxTest.Models.Home
{
    public class IndexViewModel
    {
        public string Value { get; set; }
    }
}

…it’s just a simple POCO with a single field. The Index.js file in the folder Scripts\Home\Index.js looks like this:

$(function () {
    $('form').submit(function () {
        $.ajax({
            url: this.action,
            type: this.method,
            data: $(this).serialize(),
            success: function (result) {
                $('#Target').html(result);
            }
        });
        return false;
    });
});

This looks for a form element and wires up an AJAX call in to the form submit event using jQuery. When the AJAX call completes, any data received is written to a div called Target. If this was anything other than a simple demonstration I would handle errors with a suitable pop-up. The ‘return false;’ statement at the end is really important. This tells JavaScript not to allow the form submit event to bubble up as normal when the code declared here completes.

Next is the Index.cshtml file, which is the display part of the application:

@model AjaxTest.Models.Home.IndexViewModel
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <script language="javascript" type="text/javascript" src="@Url.Content("~/Scripts/jquery-1.9.1.js")"></script>
    <script language="javascript" type="text/javascript" src="@Url.Content("~/Scripts/Home/Index.js")"></script>    
    <title>Index</title>
</head>
<body>
    <div>
        @using (Html.BeginForm("Index", "Home"))
        {
            <div><input type="submit" value="Click to Update" /></div>
            <div id="Target">@Model.Value</div>
        }
    </div>
</body>
</html>

References to both jQuery and my own JavaScript file have been added, along with a model declaration. Inside the body tag is a normal HTML form, a submit button and the div that will be targetted by my AJAX call.

Finally, here is the code for the controller that binds everything together:

using System.Web.Mvc;
using AjaxTest.Models.Home;
using System;

namespace AjaxTest.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var viewModel = new IndexViewModel { Value = "No Value" };
            return View("Index", viewModel);
        }

        [HttpPost]
        public ActionResult Index(object formData)
        {
            var newValue = "Value: " + DateTime.Now;

            // Use an AJAX dialog if possible:
            if (Request.IsAjaxRequest())
            {
                return Content(newValue);
            }

            return View("Index", new IndexViewModel { Value = newValue });
        }
    }
}

The Get method creates a view model for the initial state of the page and renders our index page. The Post method is a little more interesting. This uses the Request.IsAjaxRequest() to determine whether the Post was performed using AJAX or good-old postbacks. If the former is true, some text (containing the time) is returned which our JavaScript function will insert into the div named Target. If not, the entire form is returned, still using the text that would have been passed back had JavaScript been enabled in the client browser.

The end result that the user receives is the same regardless of whether they have JavaScript enabled or not, but in cases where they do, a postback is avoided.

Thank you jQuery!