The power of partial views, JQuery and AJAX in ASP.NET MVC
Posted by paululvinius on June 16, 2009
One really nice benefit you get from using ASP.NET MVC is that you get structured url:s out of the box looking like this: http://www.mycoolsite.com/Products/Create, Products/List, Products/Details, Categories/List, etc. Each url maps to an action within a “controller”, that returns a “view” that is supposed to render exactly what you expect from reading the url. So, “Products/Create” tells us that we are going to see a view, where we will be able to create a product – but enough with the obvious.
While url:s specific to user actions like this make everything very structured and maintainable, we often need to cross these boundaries. What if we want to create a “product” and a “category” from the same page? A page in a website often contains combinations of different responsibilities like this common scenario: While editing a product, a user realizes that he/she wants to create a new category for the product. To solve this nicely we might want to embed a “create category” part within the “create product” view. This is where “partial views” in ASP.NET MVC come in. Additionally, we probably don’t even want the web page to reload while adding categories, making it possible to fill in half a product form, realize that you need more categories, add these, and finally submit the product form. This is where AJAX and JQuery enter the scene.
Let’s take a look at how we can implement a pattern like this in ASP.NET MVC using the scenario mentioned above. Let me first point out that there are of course a bunch of ways you can implement this, but I’ll try to give you an example of a pretty neat implementation with a couple of benefits, along with some discussions on the way. The source code can be downloaded here.
So we need to manage products and categories. To shorten things down a bit, let’s say we already have all the basic pieces put together. We can list and create products in an ordinary fashion. When we create a new product we can select a category from a list of categories in a drop down list, but we can’t create new categories quite yet. So nothing except the basics so far (note that I’m not going through all the basics in this article, see other sources for that).
Products and categories are of course two different entities in the model. They should each have its own Controller class and of course separate views for GUI rendering, maintaining “separation of concerns”. Don’t forget the twist though, we want to evolve from the standard flow of things by making it possible for a user to add categories from the “create product” view. For clarity, let’s take a sneak peek at the final input form for adding a product and/or categories.
From a strict MVC viewpoint, one could argue that we have somewhat of a philosophical conflict here since we are mixing two “concerns” in the same view, namely products and categories. But luckily there are ways you can implement this and still be a good citizen. Most importantly, we need to break out the “Add new category” GUI-part (as seen in the image above) as something called a “partial view”. Think of a partial view as a slice of a page or like a user control in ASP.NET. In the process, we’ll also have to make a couple of design decisions and, of course, deal with some technical challenges as well.
So, let’s first create the “partial view” for adding a new category. This step is pretty straight forward. First, we need to create the CategoryController class with an action method that we’ll call “Create”, and that returns a PartialViewResult.
Once you have created the action method, you can create the “view” by simply right-clicking somewhere inside the method and choose “Add View” from the context menu. The “Add View” dialog has an option for “Create a partial view”, which we want to do in this example.
In the “Create.ascx” that has now been generated for you, just add the html markup you need. Remember this is only a part of a page (again, think user control). In our case, this is where we want to create the html form for adding a new category.
The next step requires decision-making. We now want to use the newly created partial view in the hosting view. Basically, ASP.NET offers two ways of doing this.
- RenderPartial (System.Web.Mvc)
- RenderAction (Microsoft.Web.Mvc) – This is in the ASP.NET MVC v1.0 Futures.
Use RenderPartial when you need to render something that naturally is a part of the hosting view and its Model (if present). You can pass the entire model or of course any subset of it, or you can choose not to pass any model at all. Examples:
<% Html.RenderPartial("partialViewName"); %>
or if you need to pass the model…
<% Html.RenderPartial("partialViewName", Model); %>
Alternatively, use RenderAction when you need to render something that naturally is not a part of the hosting view or its Model. This is the one we are going to use in this example, since adding categories doesn’t necessarily have anything to do with adding products. We just happened to realize that we wanted to host one within the other for the soul purpose of making a more efficient user interface. Example of use:
<!— Invoke the “Create” action method in the “Category” controller and render its partial view –>
<% Html.RenderAction("Create", "Category"); %>
The next step is to make sure that we can post the “Add category” –form and handle the return logic. This requires some server side and some client side programming. We are going to communicate with data only, through JSON (so no formatting). Before digging into server side, let’s take a look at the client side for a moment. We can either choose to go entirely with JQuery, or we can use JQuery together with some built-in Ajax helpers in the Mvc framework. Let’s go with the latter, it produces less code and makes more use of the framework we’re using. The JQuery-only approach could provide a higher level of control though, and if you are a true JQuery friend this choice could be the more attractive one. Note: The downloadable source code for this article also includes the “JQuery-only approach, hidden in a html comment at the bottom of Create.ascx.
So, we are going to use the built-in Ajax helper method “BeginForm” (in System.Web.Mvc) to create the html form. This helper renders a script in the forms “onsubmit” event that takes care of the AJAX call to our server. The new version of the Create.ascx looks like this:
On the server side we need to add the action method that the client code will invoke.
To avoid any trouble, choose a different name than the (non-post) method that we just named Create earlier. If they have the same name, the RenderAction method will choose the method with the same http verb as the hosting view, and this is not always what you want. All of a sudden you could end up getting a view that tries to render pure JSON data as a GUI :) So, to take control over what action method gets used and when, the simplest way is to use unique names in these cases. However, there are also other ways to go around this issue.
That’s it, feel free to download the complete source code of course. With the helper methods of ASP.NET MVC in combination of partial views and some JQuery, there aren’t that many steps to take in order to add powerful AJAX enabled functionality to your web sites.