Wednesday, November 23, 2011
Cross Domain Support for jQuery Ajax Calls With WCF Rest Services
This summary is not available. Please
click here to view the post.
Tuesday, November 22, 2011
Asp.Net MVC ( jQuery Templates) Auto Model Binding To a Complex Type that has a Collection
Posting back collection and getting it to default bind to the controller method parameter is very interesting with Asp.Net MVC 3. This can be achieved using the DefaultModelBinder.
For primitive types it is very easy.. something like below is all you need to do at the view side
<form method="post" action="/Home/UpdateStudentIds"> <input type="text" name="studentIds" value="123" /> <input type="text" name="studentIds" value="234" /> <input type="text" name="studentIds" value="235" /> <input type="text" name="studentIds" value="834" /> <input type="submit" /> </form>
And the controller method will look like below:
public ActionResult StudentIds(ICollection<int> studentIds{ return View( studentIds) // studentIds will be a collection of int }
The above is pretty straight forward. Now, what if we have to supply a collection of complex types and that too as part of a complete object hierarchy. For e.g, let us say we need to post back a Teacher object which will have the collection of student entities in it. Just to add more spice to it, let us say that I am using jQuery templates to render the collection details dynamically on the view.
So the below is my Model ( View Model ? ) classes:
public class Teacher{ public string Name{ get; set; } public ICollection<Student> Students { get; set; } } public class Student{ public string FirstName{ get; set; } public string FirstName{ get; set; } public int StudentId {get;set;} }
And the below is my controller method :
public ActionResult UpdateTeacher(Teacher teacher) { return View(teacher); }
So now to the view. The goal is, when the user submits the form back to the server ( controller), everything should get auto bound to the teacher object – the parameter to the controller method. The teacher object should have the collection of students in it with the values passed from the view (client). Also we mentioned, we are going to use jQuery templates at the view to show the list of students the Teacher is associated with. The code for the view is below. I am providing only the razor code and not the related JavaScript code ( the jQuery template binding JavaScript code is pretty straight forward and I am not including it below).
@using (Html.BeginForm("UpdateTeacher", "Teacher"))
{
<fieldset>
<fieldset>
<!-- The teacher name -->
@Html.LabelFor(model => model.Name)
@Html.TextBoxFor(model => model.Name)
<div>
<!-- The student details -- this is the header row -->
<table id="studentTbl">
<thead>
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
</tr>
</thead>
<!-- this is the student details to be filled in by the jquery template script below -->
<tbody id="studentTblBody">
</tbody>
</table>
</div>
</fieldset>
<!-- student details - row by row -->
<script id="studentDetailsTemplate" type="text/x-jquery-tmpl">
<tr>
<td>
<input type="hidden" name="Students.Index" value="${StudentId}" />
<input type="hidden" name="Students[${StudentId}].StudentId" value="${StudentId}" />
${FirstName}
<input type="hidden" name="Students[${StudentId}].FirstName" value="${FirstName}" />
</td>
<td>
${LastName}
<input type="hidden" name="Students[${StudentId}].LastName" value="${LastName}" />
</td>
</tr>
</script>
<!-- and finally the button to submit -->
<fieldset>
<div>
<input type="submit" value="Save" id="Save" />
</div>
</fieldset>
</fieldset>
}that is it….rest is magic
Line 28 to line 41 is what does it. If you watch closely, for each row, for each element, we have added an input tag to represent that element. Inside here we need to recreate the collection in such a way that when the whole data is sent back, the DefaultModelBinder will be able to bind it to the action parameter. The name of the elements is what the DefaultModelBinder uses to create the collection. So if the names are indexed, then it will create a collection with the same name. The name of the collection inside the teacher is Students. So the name of each of these elements should also be indexed around the “Students” name. And also to provide an unique index to each of the element for each row, we have used the StudentId property since it will be unique for each student. So in effect, when the data is posted back to the server, the collection is sent back like Students[123].FirstName = “XXX”, Students[123].LastName =”YYY”, Students[234].FirstName =”AAA”, Students[234].LastName = “BBB” etc. Using this information it will be able to create a collection of Students and since it comes as part of the form post which contains the teacher object details it will tie the collection to the teacher object as well.
Ok… . I would encourage the reader to take the above code snippets and try it out in a complete form.
Phil Haack had blogged about this DefaultModelBinder in his blog -- http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx -- , however one of the comments to his blog was how would you do it if the collection was part of an object hierarchy. I added the jQuery template part also to deal with the collection in the view – the project I was working on was using jQuery Templates heavily. You can get more details on the jQuery Templates at http://api.jquery.com/category/plugins/templates/ .
Code for peace!
Best,
Subscribe to:
Posts (Atom)