Async operations with jQuery Ajax and Asp.Net MVC

By design in a MVC web application every action that you perform does a post back and/or navigation to the interface that implements it. If you want to add for example a new entry in the database you’ll have to navigate to “Create a new entry” url where you have a submit button that does a post back to save the data and returns you the result. In my “Post to Wall” app I am trying to avoid such a behavior, any operation that involves calling a controller action must not redirect or post back, this can be accomplished in several ways.

Microsoft provides a helper class named Ajax, with this helper you can create an async submit form by using Ajax.BeginForm, but for my app I chose to use the $.ajax implementation from the JQuery library, I prefer to use Microsoft’s ajax only combined with the WebGrid component.  I’ve chosen the jQuery’s ajax because it makes the code easy to debug and in my opinion it’s more compact and straightforward. You can easily debug JQuery with Firefox and Firebug, just set a break point in Firebug to watch the ajax call and another break point in VS.NET in the controller’s method, it would be nice to just use VS.NET but Firebug is a must when it comes to javascript debugging.

There are several steps in order to accomplish an asynchronous data exchange:

  1. Add a jQuery event handler for the html element that triggers the action
  2. Call the controller desired action using JQuery ajax
  3. Handle the json formatted data received from the server based on the response type (success or fault)
  4. Update the user interface (html) with jQuery

Lets see this implemented in my Post to Wall app:

In Index.cshtml declare a input button like this:

Index.cshtml
<input name="submit" type="submit"  value="Post" class="post-button fg-button ui-state-default"/>

In the controller expose a JsonResult action that will perform a insert operation in the database:

TextNotesController.cs
[HttpPost]
[ValidateInput(false)]
public JsonResult PostNote(string content)
{
    string message = string.Empty;
    var n = TxtNote.CreateTxtNote(0);
    n.Title = content;
    n.Created = DateTime.Now;
    try
    {
        db.AddToTxtNotes(n);
        db.SaveChanges();
    }
    catch (Exception ex)
    {
        message = ex.Message;
    }

    return Json(new
    {
        Html = this.RenderPartialView("_NotesList", new List<TxtNote>() { n }),
        Message = message
    }, JsonRequestBehavior.AllowGet);
}

Note that this method has the ValidInput attribute set to false, I want to be able to receive information that contains characters specific to html like < > ‘ “, those  characters will be escaped so it will not break the Index.cshtml code, in order to escape the text I am using  System.Security.SecurityElement.Escape method.

The JsonResult consists of two elements, the Html that represents the new entry in the database and the a message in case any error occurs. To make the html for my new entry I am using a partial view, this view will iterate throw a list of notes and make list elements for each one, the PostNote method inserts only one note so it will generate a single li. This partial view is used to generate one or several notes html, so I can use it as well for search results method.

_NotesList.cshtml
@model IEnumerable<MvcSp.Models.TxtNote>
@using MvcSp.Helpers
@foreach (var item in Model)
{
<li class="bar-@item.Id">
    <div align="left">
        <a href="#" title="Delete" class="del-note" id="@item.Id"><span class="ui-icon ui-icon-trash" style="float:right; margin-right:10px;"></span></a>
        <a href="#" title="Edit" class="edit-note" id="edit-@item.Id"><span class="ui-icon ui-icon-pencil" style="float:right; margin-right:1px;"></span></a>
        <a href="#" title="Mail" class="mail-note" id="mail-@item.Id"><span class="ui-icon ui-icon-comment" style="float:right; margin-right:1px;"></span></a>
        <p class="note-text">@MvcHtmlString.Create(@item.Title.Prep()) <br /> <em>@item.Created</em></p>
    </div>
</li>
}

The last piece of code needed is the JQuery function:

Index.cshtml
    //post note
    $(function () {
        $(".post-button").click(function (e) {
            e.preventDefault();
            var boxval = $("#content").val();
            var dataString = 'content=' + boxval;
            if (boxval == '') {
                showError("Can't post an empty note");
            }
            else {
                showLoader('Saving note');
                $.ajax({
                    type: "POST",
                    url: "TextNotes/PostNote",
                    data: dataString,
                    cache: false,
                    dataType: "json",
                    success: function (data) {
                        if (data.Message) {
                            $("#flash").hide();
                            showError(data.Message);
                        } else {
                            $("ol#update").prepend(data.Html);
                            $("ol#update li:first").slideDown("slow");
                            document.getElementById('content').value = '';
                            $("#flash").hide();
                        }
                    }
                });
            }
            return false;
        });
    });  //end post note

This function adds a event handler to my post button using $(“post-button”).click, I am using the css class to refer the button, another way is by using the id of the element, like is done to obtain the text from  the textarea: $(“#content”).val(). the js will checks if the textarea is empty and will pop-up a jQuery UI dialog with the warning message, same for any errors occurs on the server side.

After the note is extracted from the textarea is appended to the json formatted data, I am using the same name “content=” as used in the controller method. Before starting the ajax call I am displaying a message to the user so he will know that an async operation is started, showing a gif animation is a good practice. For the rest of the js code involved in this operation you should download the project and see for yourself.

download source code files

Next post: Edit data in dialog form with JQuery and Asp.Net MVC
Previous post: Starting a new app with Asp.Net MVC 3 & JQuery UI

14 Responses to Async operations with jQuery Ajax and Asp.Net MVC
  1. Projap Reply

    Hi Stefan,
    Thanks for posting. I am trying to get it to work.
    But I can’t open your solution with VS 2010. It tries to create a virtual directory during opening and it fails.

    What virtual directory are you trying to create?

    Is it possible to get the steps to make it work?

    Thanks so much.

    • stefan Reply

      The solution is set to run in IIS 7.5 Express, you’ll need to install the prerequisites specified in this post. After you’ll open the project go to project properties and make sure is running under IIS Express http://localhost:7286/, click on ‘Create Virtual Directory’ and it’s done.

      If don’t manage to run it please let me know I will try to explain more.

  2. Cozmin Reply

    Great post Stefan,

    I’ve been trying to make this for ages. Now it’s all clear. :)

  3. [...] data in dialog form with JQuery and Asp.Net MVC Async operations with jQuery Ajax and Asp.Net MVC Starti... stefanprodan.com/2011/06/load-on-demand-and-session-sync-with-jquery-and-asp-net-mvc
  4. hvm Reply

    Hi Stefan,

    I read this post and it is very useful to me but i can’t run it in my local machine…

    when i open your solution with VS 2010 it gives virtual directory related error and project unavailable.

    Please provide exact steps or provide other solution which has no need virtual directory

    Thanks,
    HVM

    Thanks so much.

  5. stefan Reply

    I’ve updated the project, you can download it again here: http://www.stefanprodan.com/admin/code/Mvc-Post-to-Wall.zip Now it uses the Visual Studio Web Server and it should run on any VS.NET 2010 SP1 with the Mvc Tools Update installed.

  6. Jinu C Joseph Reply

    Great post Stefan. Helpful to me.

  7. Jon Reply

    As a side note, you should mention that using [ValidateInput(false)] is strongly discouraged b/c someone can put any javascript they like in the comment and anyone viewing the page afterwards will execute it.

  8. [...] Instead of validating the CAPTCHA on post, you can use an Ajax call to validate and refresh the image as... stefanprodan.com/2012/01/user-friendly-captcha-for-asp-net-mvc
  9. Vignesh Reply

    Nice Post but cant escape ?

    try posting “?” in the text area. It shows a bug. how to fix it??? please help…..

  10. swapnil Reply

    how to handle multiple ajax calls.
    I have done something similar but for a different cause.
    I have a search box, where I enter text, for each character I fetch the results, and for each result, I append a textbox with that value.

    now, when a user types really fast, the async results get out of sync and the last input , even being invalid, will show results from previous result.

    e,g I have entry in database as test, test1, test2, dummy
    user types
    t = 3 results
    e = 3 results
    s = r results
    t = 3 results
    x = 0 result = but here it shows 3 if user was quick enough to type.

    • stefan Reply

      Hi, you’ll have to add all the running ajax calls in an array, if call #3 returns faster then #1 or #2, you’ll have to cancel all ajax calls triggered before #3.

Leave a Reply

Your email address will not be published. Please enter your name, email and a comment.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>