Simple and painless Ajax in MVC3
by trouf on 27/04/2011Even though Microsoft really came through with MVC3 and added a lot of sweetness, I still find myself reluctant to use the provided Ajax-functionality.
Here’s why:
@Ajax.ActionLink("Hurf", "Durf", "Controllurf", new { param = somestuff }, new AjaxOptions { HttpMethod = "Post", OnSuccess = "Somejs" })
This approach is nice and simple, yes. But what if I don’t like having global javascript functions all over the place to handle the results of the action. It kind of pains me to see that I can use ”unobtrusive” validation functionality in MVC3 but not unobtrusive Ajax handling.
This is solved by implementing the ”ajaxification” of a normal Html.ActionLink in a separate javascript,
such as proposed here http://stackoverflow.com/questions/4878127/mvc3-ajax-actionlink.
I needed a more reusable way of doing this, but portable enough to be painlessly lifted to other projects and easy to use for other developers in the project. So i slapped together this jQuery plugin…
(function($) { /** * Ajaxify MVC3 ActionLinks * * @params { * *success : result handling function(data, textStatus, jqXHR) * *data : Data to send (accepts json data as default) * verb : Http verb to use ('POST', 'GET', ..) Defaults to 'POST' * type : dataType expected from server, Defaults to 'html' * contentType : contentType sent TO server Defaults to 'application/json' * error : error handling function(jqXHR, textStatus, errorThrown) * } * * * Usage: * $('#ajaxstuff').ajaxLink({ * data: { foo: 'Fooinator' }, * success: function (data) { console.log(data); } * }); * */ $.fn.ajaxLink = function (params) { if (!params || !params.data || !params.success) throw new Error('ajaxLink parameters missing');
//this is equal to $(this) in the current scope //save this reference for use inside nested scopes var link = this,
//Defaults to type:html, verb:POST, //content: 'application/json' verb = params.verb || 'POST', type = params.type || 'html', contentType = params.contentType || 'application/json',
//If contentType is set, do not assume json data = (params.contentType ? params.data : JSON.stringify(params.data));
//Attach eventhandler to (this) link link.click(function () { $.ajax({ url: params.url || link.attr('href'), type: verb, data: data, contentType: contentType, dataType: type, success: function (result, status, xhr) { params.success(result, status, xhr); }, error: function (xhr, status, error) { if (params.error) params.error(xhr, status, error); } });
//Stop the click from actually posting the page return false; });
};
})(jQuery);Using it is quite straightforward, or at least it seems to me at the time of writing this.
First, we create the controller action that we want to call with the Ajax link:
public ActionResult AjaxStuff(object foo) { var stuff = new { Name = "Stuff" + foo };
ViewBag.Stuff = stuff.Name;
return View();}This action returns a view, so a view will have to be created as well. A simple plain text partial view will do fine. Be sure not to load any layout for this though. The action could have returned JSON as well,
as both cases can be handled by the jQuery plugin.
With a controller action and a view in place, we create the ActionLink in the view where we need the Ajax functionality:
@Html.ActionLink("Click me!", "AjaxStuff", null, new { id = "ajaxstuff" }) There we go!, now we can declare all our events and handlers well outside the view layout as demonstrated in the following gist:
$('#ajaxstuff').ajaxLink({ data: { foo: 'Fooinator' }, success: function (data) { $('#ajaxdiv').html(data); } });
No comments yet.