Friday, November 25, 2011

jQuery's replaceWith and using it to create a new insertion mode for Ajax update targets

In an Ajax-enabled web application it is possible to update only parts of a web page after submits to the server. This allows for a great user interface experience. To partially update a page, the contents of a DOM node (e.g. a DIV element) are replaced in JavaScript by some HTML that has been returned by the web server. Using jQuery:
$("#DivElementId").html(htmlReturnedFromServer)
This replaces the contents of the element, i.e. the DIV element itself is not replaced. Sometimes it is useful or even necessary to replace a complete element, not only its children. For that we have jQuery's replaceWith method:
$("#DivElementId").replaceWith(htmlReturnedFromServer)
I recently wanted to replace a DIV element after a submit using the Ajax.BeginForm helper method in ASP.NET MVC. The unobtrusive Ajax library that ships with MVC 3 uses callbacks that are based on the four callbacks from jQuery.ajax. However, the InsertionMode = InsertionMode.Replace option from the Ajax.BeginForm method does not result in jQuery's replaceWith being called. The content of the element is replaced, not the element itself.

It turns out to be rather simple to add a 'ReplaceWith' insertion mode to MVC Ajax. For that, the file jquery.unobtrusive-ajax.js in the application's Scripts directory has to be modified. In the asyncOnSuccess function add the 'case "REPLACEWITH"' option to the switch statement:
switch (mode) {
    case "BEFORE":
        top = update.firstChild;
        $("<div />").html(data).contents().each(function () {
            update.insertBefore(this, top);
        });
        break;
    case "AFTER":
        $("<div />").html(data).contents().each(function () {
            update.appendChild(this);
        });
        break;
    case "REPLACEWITH":
        $(update).replaceWith(data);
        break;
    default:  /* Used for InsertionMode = InsertionMode.Replace! */
        $(update).html(data);
        break;
}
To activate the REPLACEWITH option we add a custom HTML attribute 'data_ajax_mode = "replaceWith"' to the Ajax.BeginForm method call:
@using (Ajax.BeginForm("AddTerm", null, new AjaxOptions { UpdateTargetId = "TermList" }, new { data_ajax_mode = "replaceWith" }))
{
  @* form contents... *@
}
Note: This code example uses the Razor view engine.

No comments:

Post a Comment