AJAX Partial Views via a JQuery Plugin

The first time we implemented code to AJAX in a Partial View we were quite happy with the results. The app we were working on was built using the traditional style of server-side rendered views but we wanted to add in some simple AJAX functionality to spruce up the User Experience. 

After implementing this code a few times one thing jumped out at us. The potential for “Spaghetti Code”. Since each action had a unique URL and DOM element to update in the view, we had to write a snippet of JavaScript code for each action, which lead to a lot of code redundancy. So eventually, we attempted to write a reusable plugin that would take care of all of our AJAX calls so we could focus on Strongly Typed Razor partial views and controller code. 

A good example of this plugin could be to AJAX in a success or error message upon submitting a Feedback form. To see this in action, you can view the feedback form at SFTool.

We will demonstrate how to use this plugin with ASP.Net MVC.


Step 1 - Initialize the Plugin



First things first. Reference the Jquery library and then reference this plugin (copy it from the end of this post). Then you can initialize the plugin, the simplest way to initialize is as follows:


$(function () {
   // initialize plugin
   $('body').initAjaxPartialView();
});

Notice the $('body'). This can be any valid DOM element and it refers to the container you want the plugin to listen to. Using $('body') will ensure that the plugin will listen to any DOM element on the page but it is also the least efficient so you may want to lower the scope to a specific section of the page rather than the entire page itself. 


If you want to fire some custom events on the success or failure of a partial view being AJAX’d, you can use the optional OnSuccess or OnError parameters and pass in your own callback functions:

 $(function () {
    // initialize plugin
    $('body').initAjaxPartialView({
       onSuccess: function () {
          console.log('success!');
       },
       onError: function() {
          console.log('error!');
       }
    });
 });   


Step 2 - Create the controller action and partial view


A trivial example of an action returning a partial view.

[OutputCache(Duration = 1)]
public ActionResult WelcomeMessage()
{
    return PartialView();
} 

However, notice the [OutputCache(Duration = 1)]. We discovered caching issues with IE even when caching was disabled in the plugin so setting OutputCache to 1sec explicitly will force IE to not cache the partial view. In this example we are returning a static partial view so we would actually want the browser to cache it so we would probably set the OutputCache to a week or month in seconds.

Step 3 - Decorate link or forms with the appropriate data-attributes


Now that we have initialized the plugin and created our action and partial view, we can now create links or forms that will initiate the AJAX’ing of the partial view. There are two required data-attributes for each link or form. They are data-ajax-action and data-ajax-target.

For hyperlinks use data-ajax-action="get"

For form submit buttons use data-ajax-action="post"

The data-ajax-target attribute is used to declare the DOM element which will be the container that you want the partial view to be loaded into. It can take any valid Jquery selector. In this example, we are using an ID selector for simplicity.


For forms, decorate the submit button with the following attributes (replace "get" with "post"):


Well, there you have it. Clicking the link or submitting the form will automatically AJAX in your partial view into the DOM element specified in the data-ajax-target. To AJAX in other partial views you simply have to create actions, partial views, and the links or forms to trigger them. No more javascript is needed. This way, you will not risk “Spaghetti Code” in your views when ajaxing many partials across your application.


Below is the plugin version:


(function ($) {
    $.fn.initAjaxPartialView = function () {

        if (!this.length > 0) {
            console.log('AjaxPartialView: init function called on invalid element');
            return this;
        }

        // merge user supplied options
        var options = $.extend({
            onSuccess: function () { },
            onError: function () { console.log('AjaxPartialView: An unexpected error has occured'); }
        }, arguments[0] || { });

        // click event handler
        this.on('click', '[data-ajax-action="get"], [data-ajax-action="post"]', function (event) {
            event.preventDefault();
            var $this = $(this);
            var action = $this.attr('data-ajax-action');
            var target = $this.attr('data-ajax-target');
            var url = '', data = [];

            // if target isn't valid DOM element
            // fire error callback and return
            if ($(target).length <= 0) {
                options.onError.call(this);
                return this;
            }

            // for gets assume hyperlink
            if (action === 'get') {
                url = $this.attr('href');
            }

            // for posts assume submit button inside form
            if (action === 'post') {
                url  = $this.closest('form').attr('action');
                data = $this.closest('form').serialize();
            }

            $.ajax({
                cache: false,
                type:  action,
                url:   url,
                data:  data,
               success: function (result) {
                    // render result inside target
                    $(target).html(result);

                    // fire success callback
                    options.onSuccess.call(this);
                },
                error: function (errorMsg) {
                    // fire error callback
                    options.onError.call(this);
                }
            });
        });

        return this;
    };

}(jQuery));


Published: 1/12/16





Comments

Popular posts from this blog

ASP.NET Identity Remember Me

IIS Express Client Certificates

ASP.NET MVC - How to enable/disable CaC/Client Certificate authentication per area or route.