This is the third post in a series about jQuery and ASP.NET MVC 2 in Visual Studio 2010.
100% of the developers I have talked to this morning are enjoying jQuery and how it makes ASP.NET MVC sites a treat to work on. Of course, the sample size was one (1) developer, and he’s writing this post. Just sayin’.
In this article I’m going to cover some of the model binding scenarios that work seamlessly with these two technologies, starting off with some background and a sample, then progressing to more complex concepts.
Model Binding Basics
Model binding occurs in the processing of a request in the MVC framework, after routing and the creation of the controller. After the controller comes out of the factory, reflection kicks in to match up the request from the routing engine (as a result of some client action) with any parameters in the HTTP request.
Said another way: form values and querystring parameters get automatically turned into .NET objects in the MVC framework. Cool.
To provide a simple overview of how model binding works, we’re going to set up a quick demonstration. Start up the IDE and create an ASP.NET MVC 2 Web Application. Delete the Index file (we’re going to create our own later). Here’s the steps we’re going to follow:
- Create a new model called Person (and build our project)
- Update our Controller to setup an “empty” person for our view
- Create a strongly-typed view to create a person
- Create an action method on our Home Controller to capture the ‘create’
- Let the MVC framework do the rest
We’re not actually going to persist anything here, this is just a show-and-tell.
The simple parts
Navigate to your Models folder and right-click to Add –> Class called Person. Complete the class out as follows:
We need to build our project here (SHIFT + CTRL + b) for the IDE to be able to see our class in later steps. The type-awareness from reflection requires that our type exist in an assembly.
Pop over to Controllers –> HomeController and delete the ViewData assignment. We’re going to create a new Person here and return it with the view. Our action looks very simply like so:
Right-click anywhere in the method and select Add View… from the context menu. We are adding a view named Index, setting it to be a strongly-typed view and setting the view content to Create. This will allow code generation to output the basics of the form we’re going to use.
Note that here, or anytime you try to add a view, that if your model hasn’t been updated by building your project your types won’t appear in the View Data Class drop-down. You can cancel, build, and re-open the dialog if that is the case.
The page that is generated is super handy as a starting point. Even if it doesn’t save me much time (after all the changes and deleting I do) for some reason it just makes me feel better that the computer had to do some work too.
Let’s clean it up a bit. Remove the validation controls, delete the DIV with the ‘back to list’ link in it and change the H2 to something more interesting.
Because I’m not going to be posting back to my Index action method, I need to also update the using statement to have to correct calls created for submitting the form:
Html.BeginForm("CreatePerson", "Home")
Finally, let’s add a bit of code with the corresponding method, CreatePerson, and a breakpoint in our Home controller:
The above doesn’t actually do anything (and won’t go anywhere past the breakpoint), but if you pause where I suggest and evaluate the Person object or the name that was assigned the string, you’ll see the values populated.
How did the Model Binding Work?
There are actually a ton of in-depth explanations out there, but here is the summary of what we’ve done and what the MVC framework does to support model binding:
- We have a class with public properties
- The template engine created a page for us with the HTML helper TextBoxFor
- TextBoxFor uses the name of the public properties to generate a form input with the same name
- The template creates a form to host those controls, which we directed to our controller and action
- When written to the browser, the form action is set to “/Home/CreatePerson” using the POST verb
- The MVC framework routes the form submission to the Home controller, then uses reflection to find the CreatePerson method
- Because the method accepts a Person object as a parameter, the MVC framework evaluates the HTTP request (querystring parameters, form values) and then hydrates an object for us
Now, Let’s Make it Interesting
So far, this has just been a demonstration of simple model binding in the MVC framework. Let’s get jQuery involved.
- Change the controller action to a partial view result
- Create a partial view that reveals the created person
- Add jQuery and jQuery UI to the Site.Master file
- Remove the using statement from the Index page
- Modify the input so it’s easier to select in jQuery
- Add a DIV to store the results of the create
- Add a calendar selector for the birthdate
- Submit the form via jQuery when the user clicks the button
- Clear the form when the partial view result comes back, and display the result
Let’s start by changing the method to only accept POSTs and simply returning the Person object we were passed in to the PartialView.
Right-click anywhere on the method and select Add View… from the context menu.
This time we’ll create the view as a partial, it will be strongly-typed to Person again, but we’ll set the View Content to Details.
The tooling support for the MVC Framework in Visual Studio 2010 will then create the ASCX (server control) for us with all the fields displayed.
Delete the P tag at the end of the generated control with the ActionLinks in it, leaving only the control tag at the top and the FIELDSET control.
Next, pop into Views –> Shared –> Site.Master and add jQuery to the HEAD of the master page. Let’s also add jQuery UI at this time to open the doors to some other augmentations. For full functionality you’ll need the CSS and the images folder in your project as well, and the CSS linked in the HEAD of the master page.
In Index.aspx, remove the using statement so that the form is no longer generated. This is easy if you use Visual Studio 2010’s collapsible regions (you can collapse the FIELDSET tag to see the whole using construct).
Add an ID with a value of “create-person-button” to the submit button at the bottom of Index.aspx. Lastly, before we get scripting, add a DIV to display the partial view when the person is ‘created’. These last two bits should look like the following:
On to the script
jQuery gives us a way to easily make AJAX requests via POSTing to the server. We pass in a map of data that the server is expecting. The result can be passed to a function that evaluates the results.
With the inputs setup the way they are and our placeholder…uh…holding a place, we’re all set to execute our POST.
We’ll write a helper function that will process the results of the POST operation and, of course, a jQuery ‘document ready’ event handler to setup the calendar and trap the submit button click.
Most of the code should be easy enough to follow along. The one interesting bit is that the data map need not be constructed with proper case. That is, if your fieldname is FirstName you can use FiRsTnAmE as the name in the data map and that is okay.
Run the app and enjoy!
The jQuery UI datepicker in action:
The form cleared after submit and the results of the POST displayed:
Some Caveats
At this point we don’t have any validation in place, we’re not saving to a database of any kind and we’re hooped if there’s a server-side error.
Unfortunately the jQuery POST doesn’t play nicely with unhandled exceptions that are thrown on the server. $.post is shorthand for a sub-set of the functionality (with some presets) of $.ajax, and only maps a handler for the success event (not error events).
To see this in, well, inaction change your CreatePerson action to the following:
This will instruct the MVC framework to pass the person object through to a view named “foo”, which doesn’t exist. If you run the form at this point, and submit, you’ll see no errors (unless you attach a debugger, like FireBug, to the script).
More to Come
In my next article I’m going to look at more complex data scenarios, like selections from a list and posting arrays back to the controller. I’ll also integrate some other goodies, like jQuery UI’s autocomplete, to help users pick a color.
Resources
- Download the project created in this post
- View the rest of the series
- jQuery’s web site
- Information on $.post
- Download jQuery UI
Good article, thanks for taking the time to post it!
ReplyDeleteI agree. Thank you for making this simple example!
ReplyDeleteGreat article. Thanks! I have one question though... What if I already have a display template for the person class, stored in /Views/Home/DisplayTemplates/Person.ascx
ReplyDeleteIs there a way to use that partial view instead of the CreatePerson.ascx? MVC only seems to look in the /Views/Home/ folder and not in the DisplayTemplates folder when I use
"return PartialView("Person", person);"
If I understand your question correctly, you should just be able to move your Person.ascx control to the Views/Shared/DisplayTemplates section and MVC routing will pick it up. If not, you can fire me an email and I would be happy to help out further!
ReplyDelete-James
Very well explained.
ReplyDeleteVery good example...
ReplyDelete