LA.NET [EN]

Mar 04

Yesterday we’ve seen an example that shows how you can easily add “partial postbacks” to an MVC app. Today, we’re going to take a deep dive on the client AJAX MVC API that is used to perform all the communication with the server side. As you recall, we must use an AJAX form  to get that “partial postback” behavior. As I said at the time, this is a simple post which injects some JS code for intercepting the submitting event and performing an out of band call to the server side. Lets recall the C# code used for creating the form:

<%
    var options = new AjaxOptions{
      HttpMethod = "GET",
      UpdateTargetId = "holder",
      LoadingElementId = "info",
      Confirm = "Are you sure you want to try to update this user?",
      InsertionMode = InsertionMode.Replace,
      OnBegin = "handleBegin",
      OnComplete = "handleComplete",
      OnFailure = "handleFailure",
      OnSuccess = "handleSuccess"
    };
    using( var ajaxForm = Ajax.BeginForm( "HandleAjaxUpdate",options ) )
    {
  %> 
    <!—OTHER CODE REMOVED –>
  <%}%>

If you peek on the source,you’ll see that you end up getting the following HTML:

<form action="Home/HandleAjaxUpdate" method="post"
         onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event), { insertionMode: Sys.Mvc.InsertionMode.replace, confirm: ”Are you sure you want to try to update this user?”, httpMethod: ”GET”, loadingElementId: ”info”, updateTargetId: ”holder”, onBegin: Function.createDelegate(this, handleBegin), onComplete: Function.createDelegate(this, handleComplete), onFailure: Function.createDelegate(this, handleFailure), onSuccess: Function.createDelegate(this, handleSuccess) });"> 
  <!—OTHER FIELDS REMOVED –>
</form>

As you can see, the onsubmit event is handled by the Sys.Mvc.AsynForm.handleSubmit method. Most of the info you set up on the server with the AjaxOptions instance is converted into a JS object that looks like this (formatting the previous code for better reading):

{
  insertionMode: Sys.Mvc.InsertionMode.replace, 
  confirm: ”Are you sure you want to try to update this user?”,
  httpMethod: ”GET”,
  loadingElementId: ”info”, 
  updateTargetId: ”holder”,
  onBegin: Function.createDelegate(this, handleBegin),
  onComplete: Function.createDelegate(this, handleComplete),
  onFailure: Function.createDelegate(this, handleFailure),
  onSuccess: Function.createDelegate(this, handleSuccess)
}

The only new thing going on here is that “client delegates” are created for the methods you’ve passed to the OnXXX properties. The Sys.Mvc.AsynForm.handleSubmit method is really simple: it will just serialize the fields of the form and use the internal _asyncRequest method for initiating the out of band call with the server. This method ends up performing several steps:

  • it checks the property confirm to see if you’ve passed a confirmation message that should be shown to the user;
  • tries to get the HTTP method from the anonymous JS object that was built from the info injected on the page. If you don’t set this property, you’ll end up using the HTTP  method defined by the method attribute of the HTML form element that is being submitted;
  • finds the URL that is going to be used to perform the remote call. If you don’t pass any on the AjaxOptions you’ve used on the server side, then you’ll end up with the action attribute of the current form. Notice that when you use GET, you’ll also get the body payload appended to the url (keep this in mind because there’s a size limit for an URL);
  • it creates and initializes the Sys.New.WebRequest object used for communicating with the server side. All the necessary configurations are performed here: the URL, body and HTTP verbs of the request object are configured and the headers are updated to reflect the current request;
  • it checks for the existence of a loading element (loadingElementId on the anonymous JS object that is inserted on the page). If it finds one, it will make it visible;
  • if you’ve specified a function for the onBegin property, that function will be called and it will be passed a reference to the current context (object of type Sys.Mvc.AjaxContext). If you return false, you stop the async postback;
  • it sets the request object’s callback method to another internal method that will do the remaining work when a response from the server arrives;
  • finally, it dispatches a call to the action method on the server side.

The “current context” is important and is represented by an instance of the Sys.Mvc.AjaxContext class. this class exposes “properties” which replicate most of the info that was injected on the page through the anonymous JS object. You’ll receive an instance of this type in the methods that you’ve  hooked up for the OnXXX properties. Here’s a list of available “properties”:

  • insertionMode: used for getting the insertion mode;
  • loadingElement: references the DOM element identified by the LoadingElementId property of the AjaxOptions object used on the server side;
  • response: reference to the response object returned from the server (only set after the response hsa been received);
  • request: reference to the request object used to perform the out of band call;
  • updateTarget: reference the element whose contents should be updated when the call completes and returns valid HTML.

As I’ve said, the response from the server is handled by an internal callback method defined by the platform (Sys.Mvc.MvcHelpers._onComplete if you’re curious). This is where most of the methods you specified for the OnXXX are executed and where the contents of the page are updated. here’s what happens in this method:

  • the response object of the current “AJAX context” is updated. Now, you can use it to get more info about the response sent from the server;
  • the onComplete method (if you specified one) is called. If you return false, the processing ends here;
  • If you’ve got a success code, the contents of the payload are evaluated. If you’ve returned JS from the server side (specified by setting the application/x-javascript content type header), that JS code is evaluated; on the other hand, if you’ve returned HTML, it will get appended to the specified target element using the insertion mode you’ve specified. If everything goes ok, the onSuccess method (when specified) will be called;
  • if you didn’t get a success code (that is, if the  code wasn’t in the 200-300 range, excluding the  1223 error codes), your onFailure method will be called (if you specified one);
  • if you’ve set up a loading element, it will be hidden.

And that’s all that happens in the client side when you use an “AJAX form”. Do keep in mind that if you return 304, you’ll only get the onSuccess method (nothing will be done on the response data returned – for starters,
it shouldn’t really be anything there). Another thing to remember is that all the calls go through the Network infrastructure of the client ASP.NET AJAX platform. This means that besides the hookups presented (the OnXXX methods you can specify in the AjaxOptions object), there are still others available by default by the client framework.

And that’s it for today. Keep tuned form more on ASP.NET MVC.

6 comments so far

  1. Andrew
    11:07 am - 4-8-2009

    Great deep-dive… just what I was looking for! 🙂 I hope you do more primers like this.

  2. Robert
    10:02 am - 6-29-2009

    Nice post. Have they forgotten to add a reference to the ”triggerElement”? I don”t see any way to get a reference to the element that invoked the request in, for instance the onSuccess function?

  3. lvbgtv
    5:59 am - 12-11-2009

    EebKyP zvpakghuxlan, [url=http://ohpqzosinpty.com/]ohpqzosinpty[/url], [link=http://qyoxlrjuwqay.com/]qyoxlrjuwqay[/link], http://lcntayarkptd.com/

  4. NYC escort girls
    4:14 am - 12-30-2009

    It is certainly interesting for me to read the article. Thanks for it. I like such topics and anything connected to this matter. I would like to read a bit more soon.

  5. NothingToLose
    7:17 pm - 1-23-2010

    Pretty nice blog you”ve got here. Thanx for it. I like such themes and anything connected to them. I would like to read a bit more on that blog soon.

  6. el Guapo
    4:02 am - 3-2-2010

    nothing here about validation. How to perform validation in processing of Ajax.BeginForm?