A simple pattern for AJAX with MVC
This is mostly brainstorming; I’ve written some proof-of-concept (POC) code, and would love feedback. I expect to hear that this has already been done earlier/better/prettier.
The requirements:
A very common pattern for our intranet sites is a page with search controls, a submit button, and an output section listing the results. I want to give this pattern a few features that suit my team:
- Have the page load very quickly.
- Do this by splitting the initial page load from the data load into an AJAX call.
- Have the URL persistent and readable – I can copy/paste the current URL and it always represents what I see on the page; I can mail it to others and they can make sense of it.
- Do this by adding the search parameters to the URL hash and interpreting the hash at page load time.
- Make such pages trivial to write; minimize the code.
- Do this by writing a set of JS functions that can be used to make the above “just work”.
The result:
MVC Controller methods:
1: public ActionResult Index()
2: {
3: // Very simple view with just search controls; no logic/data.
4: return View();
5: }
6:
7: public ActionResult IndexResults(string state = null, string revision = null,
8: string assignedTo = null, string keywords = null, string labs = null,
9: int[] multiselect = null)
10: {
11: // Load data, return partial view with results.
12: }
One thing to note is that the controls returned by the Index view bear the same names as the arguments for the IndexResults view. You’ll see why in a minute…
Javascript code for the page:
1: $(function () {
2:
3: $("#btnSearch").click(function () { runSearch() });
4: DD.queryHashToForm();
5: runSearch();
6: });
7:
8: function runSearch() {
9:
10: var urlObj = DD.formToQueryHash();
11: DD.ajaxPost(
12: "/Issues/IndexResults",
13: urlObj,
14: function (res) {
15: $("#divResults").html(res);
16: }
17: );
18: }
That’s it; together, these ingredients result in a page with a persistent URL that loads the data using AJAX, and even displays a progress indicator during the load. As you can see, this is code that’s very easy to write if you were making such a page.
So – here are the interesting lines from the JS above (note that “DD” is the library containing all the POC code):
Line #3: This just causes a button press to re-run the search.
Line #4: This takes the current URL’s hash value and interprets it like a traditional querystring. It parses it, finds controls on the page which match the keys in the hash, then assigns values to those controls as per the hash.
- So as the page loads, the first thing it does it populate the form based on the URL, then runs the search.
Line #10: This is the opposite of line #4 – it looks at the controls on the page, and creates an object from them with a property for each control’s value. It returns that object for use in the AJAX call, but then also serializes the object into the URL, in the same format expected by line #4.
Line #11: This custom method runs a normal AJAX post using jQuery, but wraps it up in before/after code that shows a default progress indicator.
Line #13: Note that we’re passing the object generated in line #10 into the AJAX call as the data.
- This relies on the fact that the MVC model binder will take a JSON object and split it into a controller method whose arguments correspond to that object’s properties; the MVC framework takes care of the heavy-lifting here.
Is this interesting? Should I post some of the code?
Comments
- Anonymous
August 22, 2011
I find it very interesting, and would love to look under the hood at the DD library. I've backed into implementing some of the same functionality in a very ad-hoc fashion, and am trying to clean it up. - Anonymous
December 12, 2011
I like it. It seems like a very reasonable progression to more client side heavy pages without having to abandon a lot of the framework functionality by jumping to something like backbone.js or knockout.js backed by raw JSON APIs, for which the ASP.NET MVC framework does not have good support. You might be able to return JSON, but what about rich support for headers, content types, response codes, and hypermedia? Until the WCF Web API is released to RTM, I think a hybrid approach like the one you described is probably best for productivity and maintainability. I'd be interested in seeing some of the code powering the functionality you describe if you get the chance. - Anonymous
June 20, 2012
This sounds like a nice approach. Where do we get the DD library to use/contribute? - Anonymous
June 20, 2012
Send me an email and I'll send you the code I have. It's definitely not in a state to publish/contribute broadly.