Click here to Skip to main content
15,886,799 members
Articles / Web Development / ASP.NET
Tip/Trick

List Model Binding in MVC

Rate me:
Please Sign up or sign in to vote.
4.78/5 (15 votes)
6 May 2014CPOL1 min read 130.4K   21   7
ASP.NET MVC List Model binding

Introduction

I am new to MVC as I just started working on a project using it. I was stuck on this model binding thingy for a couple of days, so just want to share this experience. Hope it will be useful to other newbies like me.

Background

I have this master-detail (one to many) relationship in one view and the detail is represented by HTML table in which user can add/remove the rows as they like. And I want the Add method in the controller to just accept the model as a parameter. Something like this:

Image 1

I found this great article here which helped me a lot.

Using the Code

OK, just to make it simple, I will create 2 classes with master-detail relationship in the model class.

I name it AuthorModel:

C#
public class Author
   {
       public Author()
       {
           Books = new List<Book>();
       }
       public string Name { get; set; }
       public List<Book> Books { get; set; }
   }

   public class Book
   {
       public string Title { get; set; }
       public DateTime PublishedDate { get; set; }
   }

Next, we add controller and view into the project:

Controller :

ASP.NET
public class AuthorController : Controller
    {
        //
        // GET: /Author/

        public ActionResult Index()
        {
            var model = new Author();
            return View(model);
        }
      
    } 

View :

ASP.NET
@using MvcModelBinding.Models
@model MvcModelBinding.Models.Author
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
    Index</h2>
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Author</legend>
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        <div>
            <input id="btnAddBook" type="button" 
            onclick="addRow();" value="Add Book" />
        </div>
        <table>
            <thead>
                <tr>
                    <td>
                        Title
                    </td>
                    <td>
                        Published Date
                    </td>
                </tr>
            </thead>
            <tbody id="tbBooks">
            </tbody>
        </table>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>  


Since the idea is we can add/remove the books in the client side, then only submit it to the server after we are satisfied. The client script looks like this:

JavaScript
<script language="javascript" type="text/javascript">
        function addRow() {

            @{
                Model.Books.Add(new Book());
            }

            var index = $("#tbBooks").children("tr").length;

            var indexCell = "<td style='display:none'><input name='Books.Index' 
            type='hidden' value='" + index + "' /></td>";
            var titleCell = "<td><input id='Books_" + index + "__Title' 
            name='Books[" + index + "].Title' type='text' value='' /></td>";
            var publishedCell = "<td><input id='Books_" + index + "__Title' 
            name='Books[" + index + "].PublishedDate' type='text' value='' /></td>";
            var removeCell = "<td><input id='btnAddBook' type='button' 
            value='Remove' onclick='removeRow(" + index + ");' /></td>";

            var newRow = "<tr id='trBook" + index + "'>" + 
            indexCell + titleCell + publishedCell + removeCell + "</tr>";
            $("#tbBooks").append(newRow);
        }

        function removeRow(id) {
            var controlToBeRemoved = "#trBook" + id;
            $(controlToBeRemoved).remove();
        }
    </script>

Note that the hidden value part below is necessary to allow arbitrary indices.

JavaScript
var indexCell = "<td style='display:none'>
   <input name='Books.Index' type='hidden' value='" + index + "' /></td>";

If we didn't add this extra hidden input, removing n index in the collection will also remove the subsequent items; for example: if you have 3 items in the collection, removing item number 2 will also remove item number 3.

Now let us add code in the controller to display the result:

ASP.NET
[HttpPost]
public string Index(Author author)
{
           var sb = new StringBuilder();
           try
           {
               sb.AppendFormat("Author : {0}", author.Name);
               sb.AppendLine("<br />");
               sb.AppendLine("--------------------------------");
               sb.AppendLine("<br />");
               foreach (var book in author.Books)
               {
                   sb.AppendFormat("Title : {0} | Published Date : {1}", book.Title, book.PublishedDate);
                   sb.AppendLine("<br />");
               }
           }
           catch(Exception ex)
           {
               throw ex;
           }

           return sb.ToString();
}

Observe that the controller only accepts Author model as the parameter.

Here are some of the results:

Image 2

Delete the second item:

Image 3

Image 4

That's it! Hope it helps.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Indonesia Indonesia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseExcellent Pin
Member 110937703-Mar-21 23:19
Member 110937703-Mar-21 23:19 
QuestionGreat Thanks Pin
Member 141410345-Feb-19 9:08
Member 141410345-Feb-19 9:08 
GeneralMy vote of 4 Pin
Assil14-Dec-15 14:19
professionalAssil14-Dec-15 14:19 
Questionalways getting null model on HttpPost method Pin
kittytaneja3-Sep-15 20:46
kittytaneja3-Sep-15 20:46 
QuestionError on removal Pin
Nwolisa8-Mar-15 21:47
Nwolisa8-Mar-15 21:47 
AnswerRe: Error on removal Pin
atti.b18-Dec-15 5:13
atti.b18-Dec-15 5:13 
QuestionA bit more help if possible Pin
papirc13-Jan-15 3:24
papirc13-Jan-15 3:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.