Category Archives: AJAX

MVC 3 Unobtrusive AJAX Improvements

I started experimenting this week with MVC 3 and the new unobtrustive javascript frameworks, both for AJAX and validation. These are built around jQuery, and frankly are very nice pieces of work. There are, however, a few improvements that can be made to the Javascript files included in the distribution. You can obviously include these changes manually, it’s pretty simple, but hopefully one day Microsoft will roll these up in the next version.

I’m not sure how the unobtrusive stuff is licensed by Microsoft, so I won’t publish the modified code here until I’m certain it’s okay. I will, however, go over the modifications so that you can do them yourselves.

  1. Use fn.delegate instead of fn.live – By default, the unobtrusive AJAX library uses fn.live to monitor for anchor click and form submit events, and if the elements are set to operate using AJAX they are intercepted and an AJAX request is initiated.  However, this can be inefficient because the selector is actually being fired during during document.ready, even though it isn’t used for anything.  This means every single form, submit button, and link on your page is being checked for a data-ajax=”true” attribute during document.ready for no reason.  By using $(document).delegate(selector, eventType, fn) this is completely avoided. Note: This only works using jQuery 1.4.2 or later.
  2. Cache jQuery Objects – While this is a minor efficiency concern, there are several places with the event handlers where $(form) is called multiple times to convert an element into a jQuery object with a single member.  It is much more efficient to cache $(form) in a local variable and reuse it. You can also make finding the form more efficient using .closest(‘form’) instead of .parents(‘form’)[0].
  3. Inefficient Handling Of Null Callbacks – asyncRequest uses getFunction to get a callback function based on data attributes.  This is nifty system, because can take either a function name or inline javascript code.  However, if there is no function specified, it goes through the trouble of using Function.constructor to create an empty function.  This can be avoided by adding “if (!code) return $.noop;” to the beginning of getFunction.
  4. Global AJAX Events – Currently, there is no way to attach global AJAX event handlers that specifically handle only the MVC related AJAX events.  Your only options are to intercept ALL jQuery AJAX events, or to attach events to each specific AJAX request using data attributes.  However, there are definitely use cases for global event handlers that only affect MVC related AJAX events.  Therefore, I recommend updating the “asyncRequest” function to add information to the options passed to $.ajax.  In particular, during the $.extend(options, {…}) I am adding “mvcRequest: true” and “mvcTargetElement: element”.  Now you can attach global jQuery AJAX handlers using $(document).ajaxSuccess, etc, and then test to see if it is an MVC request.
  5. AJAX Updated Forms Validation – In the current implementation of the unobtrusive validation, it can’t handle forms added to the page via an AJAX request.  You have to manually call $.validate.unobtrusive.parse() after the page update before client-side validation resumes.  This can be addressed using a global handler, so long as #3 above is also implemented.  By using the attributes passed in, we restrict the processing so it doesn’t re-parse the entire document, only the updated region. The code for this is below:
$(document).ajaxSuccess(function (event, xhr, settings) {
    if (settings.mvcTargetElement) {
        $(settings.mvcTargetElement.getAttribute("data-ajax-update")).each(function () {
            $.validator.unobtrusive.parse(this);
        });
    }
});

Please let me know if you see any other improvements that I’ve missed. I’m just beginning to dig through things, so I’ll keep updating as I find more as well.

jQuery.themescript 1.1.0 Released

Today I’ve released version 1.1.0 of jQuery.themescript.  This release includes some significant improvements that make it far more functional in the real world.

The original design concept was for a web store framework I was working on.  I wanted each store be able to easily change their javascript based themes without making changes to the javascript files for the basic theme.  This made for a much easier file based deployment of new versions to each store.  The obvious downside is that you’re downloading lots of extra javascript, particularly if you’re turning features back off that were in the basic theme.  This type of functionality is only useful in certain cases, and is never the most efficient system possible with regards to performance and bandwidth, just maintainability.

This new release still maintains that basic functionality, but now I address a more common concern as well, applying themes to AJAX updates.  In order to support this, I’ve added several new features.

  • $.themescript.exec now accepts a context parameter.  This can be a jQuery object or an HTML DOM element, just like the context to jQuery’s jQuery(selector, [context]) selector function.  All registered functions will receive this context as a parameter, and it will be automatically used as the context to selector-based theming to restrict the elements returned.
  • themescript is a new function added to jQuery objects which allows you to execute the themescripts against a specific jQuery object.  $(‘#selector’).themescript() is equivalent to $.themescript.exec( $(‘#selector’) )
  • themescript( url, [data], [callback] ) works just like the jQuery load method, except that it will automatically run themescripts against the updated HTML if the request is successful.

You can also easily add support for jQuery.themescript to ASP.Net AJAX partial page updates (a.k.a. UpdatePanels).  Just add this script code to your files and the themescripts will be automatically executed against any UpdatePanels which are changed during an asynchronous postback.

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_pageLoaded(function(sender, args) {
    var</span> updated = args.get_panelsUpdated();
    if</span> (updated && updated.length) {
        $.themescript.exec($(updated));
    }
});

Here are the links where you can access the GitHub repository or download the files:

GitHub
Download

jQuery.Net

In the last few months, I’ve discovered jQuery and jQuery UI, which are a pair pretty awesome of open source javascript libraries.  I know, I’m a little behind the times here, but all I can say is “Wow”.  Frankly, using jQuery makes the AJAX library that comes with .NET 3.0/3.5 from Microsoft seem foolish and clunky.  I’ve now transitioned away from using Microsoft’s open source AJAX Control Library, instead choosing to use jQuery.

The only downside of using jQuery with ASP.Net is the lack of integration.  They now include a vsdoc file which helps with Intellisense, but there’s a long way to go.  For simplicity, I’m still using Microsoft’s AJAX code for their page methods and UpdatePanels, and primarily using jQuery for the client side controls and animations.

I’ve written a library to help with the creation of ASP.Net server controls that utilize jQuery.  I’m calling it, very creatively, jQuery.Net.  You can access the code and binaries for the library on github, the link’s below.

jQuery.Net Git Repository

Fix To GroupedUpdatePanel

After further testing, I discovered a bug in my GroupedUpdatePanel. It didn’t always function correctly when the postback was initiated by a child control with ChildrenAsTriggers set to true. Any UpdatePanels declared after the initiated panel would update, but those before would not. I’ve corrected this, though it’s now a bit more complicated. There is an processing module which needs to be added to your web.config file in the section. Here’s the link to the corrected file.

GroupedUpdatePanel.zip

Grouping Update Panels

Without a doubt, AJAX is one of the most useful web development tools out there. Through AJAX, we finally have a method for developing web pages with robust user interfaces.

The most common and simplest method of AJAX development on ASP.NET is to use the UpdatePanel. While the UpdatePanel creates a lot of overhead, it is very simple to implement. However, sometimes you will have multiple UpdatePanels on a page that relate to each other. In order to reduce your overhead, you will probably want to set thier UpdateMode to Conditional. With the Conditional UpdateMode enabled, they will only update under three conditions (note that nested UpdatePanels are a bit more complicated):

  1. A child control of the UpdatePanel performs a postback, and ChildrenAsTriggers is true
  2. The Update method is explicitly called.
  3. A manually defined trigger is fired.

However, this doesn’t help with firing the other UpdatePanels on the page that are related. While you can update the other panels manually using the Update method or triggers, that can potentially be a lot of work and difficult to maintain.

In order to address this, I’ve created a simple GroupedUpdatePanel. It has a GroupName property which is used to group multiple GroupedUpdatePanels together. If any one UpdatePanel in a group is updated as part of an asynchronous postback, they will all be updated.

There are two important restrictions to note. First, you must set UpdateMode to Conditional. If any one GroupedUpdatePanel in a group is set to Always, they will all update every time. This is a result of the limitations of inheriting from the UpdatePanel class. Second, all of the UpdatePanels must be created and on the page at the time the PreRender event occurs. I’ve seen some reports on the web of certain situations where this is not the case, though I haven’t tested for any of it.

You can download the source for the control here. Feel free to use it in your own applications.

UPDATE: Please see updated version here