Working With JQuery Ajax API on ASP.NET MVC 3.0 - Power of JSON, JQuery and ASP.NET MVC Partial Views

In this post, we'll see how easy to work with JQuery AJAX API on ASP.NET MVC and how we make use of Partial Views to transfer chunk of html from server to client with a toggle button example.
2011-09-09 20:23
Tugberk Ugurlu


JQuery-logo

So, here it is. Nearly every blog I occasionally read has one JQuery related post which has JQuery ‘write less, do more’ logo on it. Now, I have it either Smile This is entirely not the intention of this blog post. What the real intention of this blog post is to lay down some useful stuff done with JQuery Ajax API on ASP.NET MVC 3.0 framework.

I am no expert on neither JQuery nor JavaScript but I am working on it and I hit the resources so hard nowadays. I am no expert on ASP.NET MVC either but I am sure I am pretty damn good at it. It is my favorite platform since v1.0.

ASP.NET MVC embraces the web (html, http, plain JavaScript) and enables you to move which direction you want on your layout. I mean you can real have your way. So, it is so important here to be able to use JavaScript (for most, it is not JavaScript anymore. It is JQuery. Don’t be surprised if you see Content-Type: text/jquery response header) as Ninja in order to get the most out of ASP.NET MVC’s V part (V as in View).

Easiest way to get JQuery package into your ASP.NET MVC 3.0 project is to do exactly nothing. No kidding, it is already there if you install the ASP.NET MVC 3 Tools Update

If you would like to get the latest version of it (which the below samples has been written on), simply type Update-Package JQuery inside PMC (Package Manager Console) and hit enter and you will be done !

Let’s get it started then.

Overview of the Process

Setting expectations correctly is the real deal. We need to set them correctly so that we will be as satisfied as we planned. In this quick blog post, I will walk you through a scenario: a basic to-do list application. We will:

  • Make AJAX calls to our server,
  • Display loading messages while processing,
  • Make use of partial views when we need to update our web page seamlessly.

File New > Project > ASP.NET MVC 3 Web Application > Internet Application > Razor View Engine > No thanks, I don’t want the test project > OK

So the mini title above actual explains what we need to do first, briefly Smile What I would like to do first is to set up my model, ORM (I will use Entity Framework for that) and database.

The main concern of this blog post is AJAX API usage on ASP.NET MVC so I am not go through all the steps of creation our model, database and all that stuff. I will put the sample code at the bottom of this blog post so feel free to dig into that

Then I will make sure to update my JQuery Nuget package to the latest one. I will tweak the default application a little bit as well.

Go get him tiger

Now we are all set up and ready to rock. Let’s begin.

imageOur database here is so simple as you can see on the left hand side. I have created the database with SQL Server Compact edition because database is not the point we are emphasizing on this post.

Our application will only consist one page and we will do all the work there.

First, I will create the JQuery structure. As I mentioned, we will display user friendly loading message to the end user. In order to do that, we will use JQuery.UI dialog api. We will have it inside our _layout.cshtml page (the reason why we do that is to be able to use it everywhere without writing it again. This app might contains only one page but think about multiple page apps for this purpose).

The code for that is really simple actually. We will only have a section defined as html code inside the DOM and we will turn that into a JQuery.UI dialog for loading messages.

Below is the html code for our loading box :

        <div id="ajax-progress-dialog">
            <div style="margin:10px 0 0 0;text-align:center;">
                <img src="@Url.Content("~/Content/img/facebook.gif")" alt="Loading..." />
            </div>
        </div>

Very simple html (please forgive me for putting the style code inline Smile). The below JQuery code will handle this html code :

        (function () {
            $(function () {
                //Global ajax progress dialog box
                //Simply run $("#ajax-progress-dialog").dialog("open"); script before the ajax post and
                //$("#ajax-progress-dialog").dialog("close"); on the ajax post complate
                $("#ajax-progress-dialog").dialog({
                    autoOpen: false,
                    draggable: false,
                    modal: true,
                    height: 80,
                    resizable: false,
                    title: "Processing, please wait...",
                    closeOnEscape: false,
                    open: function () { $(".ui-dialog-titlebar-close").hide(); } // Hide close button
                });
            });
        })();

With this approach, we set up an environment for ourselves to open this dialog when we start the AJAX call and close it when the action is completed.

Some of you guys probably think that .ajaxStart() and .ajaxComplate() would be a better fit here but I don’t. They will hook up the functions for all the AJAX calls but we might need separate loading messages. With the above approach we will call the global loading message only when we need it.

imageNow we can move up. I have added some items to the list manually and list then on the page and we have the result as the picture on the left side.

It is quite simple yet but don’t worry, it will get messy in a moment. First thing that we will do here is to add a functionality to enable toggling IsDone property of the items. When we click the anchor, the To-Do item will be marked as completed if it is not and vice versa.

Let’s look at the view code here before doing that because there is some fundamental structure for our main purpose here :

@model IEnumerable<JQueryAJAXToDoListMVCApp.Models.ToDoTB>

@{
    ViewBag.Title = "Tugberk's To-Do List";
}

@section Head { 
    <script>
        (function () {
            $(function () {
                //JQuery code will be put here
            });
        })();
    </script>
}

<h2>Tugberk's To-Do List</h2>

<div id="to-do-db-list-container">
    @Html.Partial("_ToDoDBListPartial")
</div>

As you can see have rendered a partial view here. The complete partial view code is as follows :

@model IEnumerable<JQueryAJAXToDoListMVCApp.Models.ToDoTB>

<table style="width:100%;">

    <tr>
        <th>Item</th>
        <th>Creation Date</th>
        <th>IsDone</th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>@item.Item</td>
        <td>@item.CreationDate</td>
        <td>@item.IsDone</td>
    </tr>   
}

</table>

So why we did that is a good question in this case. When we need to make a change to our list view through an AJAX call, we will render this partial view on our controller method and send it back to the client as JSON result. This partial view will be our template here. When we make a change to this partial view, this change will be made all of the places that use this partial view which is kind of nice.

Also, this action will show us one of the main fundamentals of ASP.NET MVC which is separation of concerns. View doesn’t care how the model arrives to it. It will just displays it. The same is applicable for controller as well. It does not care about how the view will display the model. It will just pass it.

Let’s put the above paragraph in action. First, we need to make a little change to our partial view for toggle function :

@foreach (var item in Model) {
    <tr>
        <td>@item.Item</td>
        <td>@item.CreationDate</td>
        <td>
            @if (@item.IsDone) { 
                <a class="isDone" href="#" data-tododb-itemid="@item.ToDoItemID">Complated (Mark as Not Complated)</a>
            } else { 
                <a class="isDone" href="#" data-tododb-itemid="@item.ToDoItemID">Not Complated (Mark as Complated)</a>
            }
        </td>
    </tr>   
}

With this change, we make the DOM ready for the JQuery. Let’s look at the JQuery code for the toggle action :

        (function () {
            $(function () {

                function toggleIsDone(e, element) {

                    var itemId = element.attr("data-tododb-itemid");
                    var d = "itemId=" + itemId;
                    var actionURL = '@Url.Action("toogleIsDone", "ToDo")';

                    $("#ajax-progress-dialog").dialog("open");

                    $.ajax({
                        type: "POST",
                        url: actionURL,
                        data: d,
                        success: function (r) {
                            $("#to-do-db-list-container").html(r.data);
                        },
                        complete: function () {
                            $("#ajax-progress-dialog").dialog("close");
                            $(".isDone").bind("click", function (event) {
                                toggleIsDone(event, $(this));
                            });
                        },
                        error: function (req, status, error) {
                            //do what you need to do here if an error occurs
                            $("#ajax-progress-dialog").dialog("close");
                        }
                    });

                    e.preventDefault();
                }

                $(".isDone").bind("click", function(e) {
                        toggleIsDone(e, $(this));
                });

            });
        })();

Let’s bring that code down into pieces. First, we bind toggleIsDone(e, element) as a click function to every element whose class attribute is ‘isDone’ and we know that they are our toggle anchors. On the toggleIsDone function, we will grab the itemId of the clicked item from data-tododb-itemid attribute of clicked anchor. Then, we will set the itemId as parameter on d variable.

Look at the actionURL variable. What happens there is that : we assigning the URL of toogleIsDone action of ToDo controller.

Before we begin our AJAX call, we simply fire up our loading dialog to display that we are doing some stuff.

On the AJAX call, we make a post request to actionURL and we are passing the d variable as data. We know that we will get back a JSON result which contains a data property and on success event of the call we simply change the content of to-do-db-list-container element with the new one which we have received from the server as JSON result.

Just before we step out the success event, we do very tricky stuff there. It is tricky in this case and hard to figure it out if you are new to JQuery. I will try to explain what we did there. We bind toggleIsDone(e, element) as a click function to every element whose class attribute is ‘isDone’. The weird thing is the fact that we have done the same just after the DOM has loaded. So, why the heck do we do that? We have bind the specified function to specified elements just after the DOM has loaded. That’s fine. Then, we have update the entire content of to-do-db-list-container div and the all click event that we have bind has been cleared out. In order not to lose the functionality, we have bind them again.

This kind of an Inception way is the best way that I come up with for this functionality and if you thing there is a better one, let me know.

On complete event, we made sure to close our loading dialog.

At the end of the code, we call a function called preventDefault() for the event. What this does is to prevent the anchor to do its default function which would be the append the # to the URL. Not necessary here but it is kind of nice to use here though.

So far, we have completed our work on client side code and lastly, we need to implement the server side function which updates the database according to parameters and sends a JSON result back to the client.

Before we do that we need to use Nuget here to bring down a very small package called TugberkUg.MVC which will have a Controller extension for us to convert partial views to string inside the controller.

image

image

The complete code of out ToDoController is as indicated below :

using System.Linq;
using System.Web.Mvc;
using TugberkUg.MVC.Helpers;
using System.Data.Objects;
using System.Data;

namespace JQueryAJAXToDoListMVCApp.Controllers
{
    public class ToDoController : Controller {

        private readonly Models.ToDoDBEntities _entities = new Models.ToDoDBEntities();

        public ActionResult Index() {

            var model = _entities.ToDoTBs;

            return View(model);
        }

        [HttpPost]
        public ActionResult toogleIsDone(int itemId) {

            //Getting the item according to itemId param
            var model = _entities.ToDoTBs.FirstOrDefault(x => x.ToDoItemID == itemId);
            //toggling the IsDone property
            model.IsDone = !model.IsDone;

            //Making the change on the db and saving
            ObjectStateEntry osmEntry = _entities.ObjectStateManager.GetObjectStateEntry(model);
            osmEntry.ChangeState(EntityState.Modified);
            _entities.SaveChanges();

            var updatedModel = _entities.ToDoTBs;

            //returning the new template as json result
            return Json(new { data = this.RenderPartialViewToString("_ToDoDBListPartial", updatedModel) });
        }

        protected override void Dispose(bool disposing) {

            _entities.Dispose();
            base.Dispose(disposing);
        }

    }
}

When you look inside the toogleIsDone method, you will see that after the necessary actions are completed, we will pass a model to our partial view which we have created earlier, render it and finally return it to the client as JSON. Why we return it as JSON instead of content is a totally subjective question in my opinion. For me, the advantage of JSON result is to be able to pass multiple values. For example, we would pass the result as follows if we needed :

            return Json(
                new { 
                    CustomMessage = "My message", 
                    data = this.RenderPartialViewToString("_ToDoDBListPartial", updatedModel) 
                });

Now when we compile our project and run it, we will see a working application :

image image image

Also, here is a quick video of a working example :

Summary

What we need to get out of from this blog post is to see that what we are capable of doing with a little effort for very usable and user friendly web pages. Also, we can visualize how things fit together and flow on your project. There are lots of way of making calls to your server from client side code and lots of them have its own pros and cons.

I hope that this blog post helps you, even a little, to solve a real world problem with your fingers Smile



Comments

Tyron
by Tyron on Friday, Nov 18 2011 22:07:47 +02:00

"Just before we step out the success event, we do very tricky stuff there."

Wouldn't it be better to use jQuery's live function? In the global scope, just change "bind" for "live", i.e.:

 

$(".isDone").live("click", function(e) {

toggleIsDone(e, $(this));

});

 

As of jQuery 1.7 (released few weeks ago), the "live" method has been deprecated, on behalf of "on" event. I didn't read about it, but surely it may achieve the same results.

 

tugberk
by tugberk on Saturday, Nov 19 2011 11:06:57 +02:00

@Tyron

yeah, you are right about that. .live() has been deprecated as stated here.

also you are totally right about your suggestion there as well. I will look into .on() event and I hope I will update the article for both live & on examples. Thanks a lot!

Quang
by Quang on Saturday, Nov 26 2011 10:04:06 +02:00

Great MVC ajax article. Thanks for sharing.

ddd
by ddd on Thursday, Jan 19 2012 03:48:28 +02:00

your english sucks

Tugberk
by Tugberk on Thursday, Jan 19 2012 10:26:28 +02:00

@ddd

:D I am pretty sure that it is way better than yours. At least I know where to capitalize letters.

Frank
by Frank on Saturday, Jan 21 2012 09:00:48 +02:00

Even though your English may not be perfect, you speak it better than I speak your language (and I would venture to guess that you speak English better than @ddd speaks your language). Thanks for sharing your work.

Ryan
by Ryan on Tuesday, Feb 21 2012 05:21:37 +02:00

@Tugberk Thanks for such a good article! :) Are you able to use the application (i.e., click the links and mark items as complete) when JavaScript is turned off?

Tugberk
by Tugberk on Tuesday, Feb 21 2012 09:55:31 +02:00

@Ryan

No, you're unable to use this if JavaScript is turned off.

You can do some coding and enable a fallback mechanizm with vanilla http post.

Muthu
by Muthu on Wednesday, Mar 07 2012 04:26:03 +02:00

Hi Tugberk,

Thank you for the great article. 

 It is tricky in this case and hard to figure it out if you are new to JQuery. I will try to explain what we did there

I'm new to Jquery and the above trick saved hours of time. Once again thanks and keep up the good work


sheir
by sheir on Saturday, Apr 14 2012 20:01:34 +03:00

What I would like to know is if the partial view has some logic in it based on some properties of its viewModel, such as only show an image if some condition is true.  Then on a click of the image, show a div containing some other properties (using the jQuery UI "toggle").

Seems like replacing the main DIV containing the partial view, will not be correct/expecte behaviour (for scenario above).

I am new to all this too and am trying to learn as fast as possible.

What I would like is to send down the updated ViewModel via JSON (or a portion of it if it is large -- just the required properties for the partial view) and then on the ajax.Success function, somehow update the client-side VM.

 

How to get that done?

venkatesh
by venkatesh on Wednesday, Feb 27 2013 10:00:46 +02:00

Hello sir,

My task is to show grid while loading the page i.e(showing list in index action method)

then i have add button below grid. when user clicks add i would like to show div which consists of text box fields for entering the data.when user submits data data should be added to data base and grid should be filled and div should not be visible.(please dont use j query) similarly simple binding when edit option is clicked in grid.(MVC3)

slots
by slots on Saturday, Dec 21 2013 01:32:00 +02:00
That's a smart answer to a difficult question.
Red Taz
by Red Taz on Wednesday, Mar 26 2014 13:15:09 +00:00
It might be worth mentioning that your javascript snippet for toggleIsDone should be run through the razor engine and not served as a plain javascript due to the call to @Url.Action. Might save someone some confusion. Thanks for the article.

New Comment