Tuesday, February 7, 2012

Dynamically adding a collection of objects in a MVC view

In one of my projects I needed to dynamically display fields to enter information for a collection of objects. Specifically speaking I had a POCO "User" class with FK to a POCO "Child" class. I needed a way to generate text boxes based on how many kids a user had. This involves several steps and here's what I had to do.

1. Create a partial view with the fields you need to capture the info for a "Child"

@{
    var seed = ViewBag.Seed;
      
    
@{ @*MVC renders fields for a collection by appending an index, which I am setting up below*@ var ageIdText = "Children_" + seed + "__Age"; var ageNameText = "Children[" + seed + "].Age"; var genderIdText = "Children_" + seed + "__Gender"; var genderNameText = "Children[" + seed + "].Gender"; var deleteIdText = "Children_" + seed + "__Delete"; var deleteNameText = "Children[" + seed + "].Delete"; }    Remove
}
MVC renders controls for collections by attaching an index for the collection. I had to code this in to render based on the number of controls that need to be displayed. Ex: the age text field will be Children_[1]__Age and so forth. I will explain the reason for having a delete field a little later. 2. Create an action in the controller that will return the partial view
public ActionResult RenderChildren(int? id, int? seed, string viewType)
        {
            //if no of children to be rendered in the view was not send in the request url, then render only one child
            if (id.HasValue)
                ViewBag.Children = id;
            else
                ViewBag.Children = 1;

            //if the collection index was not indicated, then start rendering the controls from 0. 
            //This will come in handy when there are already controls on the page and we want to add more.
            if (seed.HasValue)
                ViewBag.Seed = seed;
            else
                ViewBag.Seed = 0;
            return PartialView(viewType);
        }
It is important to keep track on the index for the collection, or you will get unexpected results.

3. Create the javascript that will call the action above from another control. ex: onclick event of a link that should add the control for adding a "Child"
function addChild(method,container,type) {
    var noofChild = $(container).find('.mark-for-delete').length;
    $.get('/account/'+method+'?seed=' + (noofChild)+"&viewtype="+type, function (template) { $(container).append(template); });
}
4. Call the javascript
Add a child
function deleteChildren(element, deleteElement) {
    $container = $(element).parent();
    $container.find(deleteElement).val('True');
    $container.hide();
}
This will take care of dynamically rendering the required number of fields for "Child" 5. Handling the deletes - I also needed to provide the user to delete existing fields
Remove
To handle the delete I need some more javascript code that will add some value to the hidden field that I added to my partial view. This value can then be picked up via the model while updating the database. I do have a property in the "Child" POCO class for setting the delete value. This field is not mapped to the database.

No comments:

Post a Comment