Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is an MVP ASP.NET and is currently employed as .NET Software Engineer at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP.
More about me More about me
Send mail E-mail me


Microsoft Most Valuable Professional - MVP - ASP.NET

Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn RealDolmen - Rock-solid passion for ICT
I'm a speaker at TechDays Belgium and TechDays Finland

Search

Latest Twitter

    Follow me on Twitter...

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    Partial page updates with ASP.NET MVC and jQuery (and action filters)

    When building an ASP.NET MVC application, chances are that you are using master pages. After working on the application for a while, it's time to spice up some views with jQuery and partial updates.

    Let's start with an example application which does not have any Ajax / jQuery. Our company's website shows a list of all employees and provides a link to a details page containing a bio for that employee. In the current situation, this link is referring to a custom action method which is rendered on a separate page.

    Example application

    Spicing things up with jQuery

    The company website could be made a little sexier... What about fetching the employee details using an Ajax call and rendering the details in the employee list? Yes, that's actually what classic ASP.NET's UpdatePanel does. Let's do that with jQuery instead.

    The employees list is decorated with a CSS class "employees", which I can use to query my DOM using jQuery:

    $(function() {
        $("ul.employees > li > a").each(function(index, element) {
            $(element).click(function(e) {
                $("<div />").load( $(element).attr('href') )
                            .appendTo( $(element).parent() );
                e.preventDefault();
            })
        });
    });

    What's this? Well, the above code instructs jQuery to add some behaviour to all links in a list item from a list decorated with the employees css class. This behaviour is a click() event, which loads the link's href using Ajax and appends it to the list.

    Now note there's a small problem... The whole site layout is messed up, because the details page actually renders itself using a master page.

    Messed-up employees list after performing an Ajax call

    Creating a jQueryPartial action filter

    The solution to this broken page is simple. Let's first create a new, empty master page, named "Empty.Master". This master page should have as many content placeholder regions as the original master page, and no other content. For example:

    <%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Empty.Master.cs" Inherits="jQueryPartialUpdates.Views.Shared.Empty" %>

    <asp:ContentPlaceHolder ID="MainContent" runat="server" />

    We can now apply this master page to the details action method whenever an Ajax call is done. You can implement this behaviour by creating a custom action filter: jQueryPartial.

    public class jQueryPartial : ActionFilterAttribute
    {
        public string MasterPage { get; set; }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            // Verify if a XMLHttpRequest is fired.
            // This can be done by checking the X-Requested-With
            // HTTP header.
            if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != null
                && filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
            {
                ViewResult viewResult = filterContext.Result as ViewResult;
                if (viewResult != null)
                {
                    viewResult.MasterName = MasterPage;
                }
            }
        }
    }

    This action filter checks for the precense of the X-Requested-With HTTP header, which is provided by jQuery when firing an asynchronous web request. When the X-Requested-With header is present, the view being rendered is instructed to use the empty master page instead of the original one.

    One thing left though: the action filter should be applied to the details action method:

    [jQueryPartial(MasterPage = "Empty")]
    public ActionResult Details(int id)
    {
        Employee employee =
            Employees.Where(e => e.Id == id).SingleOrDefault();

        ViewData["Title"] = "Details for " +
            employee.LastName + ", " + employee.FirstName;
        return View(employee);
    }

    When running the previous application, everything should render quite nicely now.

    Working example

    Want the sample code?

    You can download the sample code here: jQueryPartialUpdates.zip (134.10 kb)

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | ICT | Internet | MVC | jQuery

    Comments

    DotNetKicks.com |

    Tuesday, November 25, 2008 4:37 PM

    trackback

    Trackback from DotNetKicks.com

    Partial page updates with ASP.NET MVC and jQuery (and action filters)

    mike kidder United States |

    Wednesday, November 26, 2008 10:36 PM

    mike kidder

    Maarten,  thanks for the example....   very helpful.

    One thing I did notice is that you don't have to have the same number of ContentPlaceHolder tags from your Site.Master template.  I just used the "MainContent" to match the main area of the Site.Master.   If your Empty.Master and View both used something like "AjaxContent" instead, then your Ajax methods won't be callable via URL (not that you want to throw an exception).

    Also,  added line to JQuery code within the click event function selector to prevent duplicates if name is clicked multiple times:

         $(element).parent().children('div').remove();

    Good Stuff... Smile

    Miha Slovenia |

    Sunday, November 30, 2008 10:22 PM

    Miha

    Maarten, an interesting take on the problem, but wouldn't you say it is a workaround rather than a solution? Wouldn't you be better off writing a custom ActionResult (PartialViewResult, XHTMLFragmentViewResult or even JsonViewResult) and return that instead of a full blown view? As you really should be returning the XHTML fragment and not the whole page. I'm guessing the performance would be worse with your approach, since you're doing stuff that wouldn't be necessary if you'd taken the "custom ActionResult" approach.
    What is the benefit of using a content view (view, that is part of the "master page") anyhow? Maybe I am missing something...

    Very good content otherwise! Keep up the good work! Thanks, Miha.

    maartenba Belgium |

    Monday, December 01, 2008 7:55 AM

    maartenba

    True, this is a quick workaround for implementing partial page updates. Nicest solution is actually returning json and rendering using PURE (check plugins.jquery.com)

    Sergio Pereira United States |

    Thursday, December 04, 2008 2:26 PM

    Sergio Pereira

    @Miha, there are already JsonResult and PartialViewResult in MVC (your commented sounded like we would need to build them).
    One good thing with Maarten's approach is that you can make any existing action available via Ajax just by slapping that attribute on it. If we were to use a PartialViewResult, then we would have to check if this was an Ajax call or regular request in every one of those actions.
    I like this.

    Miha Slovenia |

    Thursday, December 04, 2008 2:50 PM

    Miha

    @Sergio: sure. It is a philosophical debate at this point. I mean, there is more than one way to do it, obviously. It is more a matter of taste what seems more 'right'. One could also argue, that partial result is a different kind of view -- in this simple case, where you simply replace it with an empty master layout, it works... All in all, it's a solution to a problem -- and that's what counts at the end of the day. Smile
    @Maarten: in the mean time, I have check out Pure, and I like it. It's a fresh approach to client-side templating.

    Sergio Pereira |

    Saturday, December 06, 2008 3:35 AM

    trackback

    Trackback from Sergio Pereira

    Reusing Views in ASP.NET MVC for Ajax Updates

    Community Blogs |

    Saturday, December 06, 2008 4:31 AM

    trackback

    Trackback from Community Blogs

    Reusing Views in ASP.NET MVC for Ajax Updates

    ASPInsiders |

    Tuesday, December 09, 2008 7:51 PM

    trackback

    Trackback from ASPInsiders

    Partial Page Updates with ASP.NET MVC and JQuery

    Joe Reynolds United States |

    Thursday, April 30, 2009 5:51 PM

    Joe Reynolds

    Mike, where did you pace the code to prevent repeats on multiple clicks? I can't get it to work.

    Joe Reynolds United States |

    Thursday, April 30, 2009 5:57 PM

    Joe Reynolds

    OK. Have the no-repeat working. I do notice that clicking the first name results in the Home button produced in the div, while clicking on other names does not. ???

    Comments are closed