Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC C# Automatic Model Binding in Nested Lists

This is my first ever C# / MVC project and I am having problems binding to a model. I have read an applied Phil Haack's Post and have used EditorFor for all my partial views. Do I need a custom Model Binder? Please help

In brief, I have a list of weeks which contain a list of entries. These entries contain a list of hours

Action:

[HttpPost]
public ActionResult SubmitRecords(List<WeekCollection> itemData)
{
     //do stuff
     return View();
}

Model:

public class WeekCollection
{
    public WeekCollection()
    {
        this.OneWeek = new List<Entry>();
    }

    public List<Entry> OneWeek { get; set; }
}

[Bind(Exclude = "Task, Project")]
public class Entry
{
    public int ProjectId { get; set; }
    public virtual Projects Project { get; set; }

    public int TaskId { get; set; }
    public virtual Tasks Task { get; set; }

    public bool Billable { get; set; }
    public List<Hours> Gethours { get; set; }
}

public class Hours
{
    public float NumberOfHours { get; set; }
}

Views (Index)

//within partial view iteration with incrementing u (u++)
@using(@Html.BeginForm())
{ 
    @Html.EditorFor(m => m[u].OneWeek, "TimesheetWeek")
    <input type="Submit">
}

Views (TimesheetWeek)

@foreach (var value in Model)
{
    v++;
    if (Model.All(x => x.projectId == 0))
    {
        @Html.DropDownListFor(p => p[v].projectId, (IEnumerable<SelectListItem>)projectList, "Select Project", new { @class = "notSelect" })
        @Html.DropDownListFor(t => t[v].taskId, (IEnumerable<SelectListItem>)taskList, "Select Task", new { @class = "notSelect" })
     }
     else
     {
        if (value.projectId != 0)
        {    
           @Html.DropDownListFor(p => p[v].projectId, (IEnumerable<SelectListItem>)projectList, new Dictionary<string, Object> { { "class", "SelectDrop" }, { "data-selectHead", value.projectId } })
           @Html.DropDownListFor(t => t[v].taskId, (IEnumerable<SelectListItem>)taskList, new Dictionary<string, Object> { { "class", "SelectDrop" }, { "data-selectHead", value.taskId } })
        }
     }

     @Html.CheckBoxFor(b => b[v].billable)
     @Html.EditorFor(h => h[v].gethours, "HoursDisplay")

     @value.gethours.Sum(a => a.numberOfHours)
     }

View (HoursDisplay)

@for (var i = 0; i < Model.Count(); i++)
{
    @Html.TextBoxFor(m => m[i].numberOfHours)
}

Model displays all the data correctly and the form data output posted is as follows:

[0].OneWeek.[0].projectId:1
[0].OneWeek.[0].taskId:1
[0].OneWeek.[0].billable:true
[0].OneWeek.[0].billable:false
[0].OneWeek.[0].gethours.[0].numberOfHours:0
[0].OneWeek.[0].gethours.[1].numberOfHours:5
[0].OneWeek.[0].gethours.[2].numberOfHours:7
[0].OneWeek.[0].gethours.[3].numberOfHours:6
[0].OneWeek.[0].gethours.[4].numberOfHours:4
[0].OneWeek.[0].gethours.[5].numberOfHours:8
[0].OneWeek.[0].gethours.[6].numberOfHours:0

I thought I got the indexing right but currently get an empty Oneweek in the action. What am I doing wrong? Any assistance is appreciated. (Some repetition and HTML has been removed)

like image 818
user1925048 Avatar asked Dec 23 '12 15:12

user1925048


People also ask

What is the C in MVC?

MVC is a design pattern used to decouple user-interface (view), data (model), and application logic (controller).

What is difference between C# and MVC?

They are the same thing. C# is the language you have used to do your development, but ASP.NET MVC is the framework you used to do it.

What is MVC stands for?

MVC (Model-View-Controller) is a pattern in software design commonly used to implement user interfaces, data, and controlling logic. It emphasizes a separation between the software's business logic and display.

Why do we use MVC in C#?

MVC is primarily used to separate an application into three main components: Model, View, and Controller. This level is considered the lowest level when compared with the View and Controller. It primarily represents the data to the user and defines the storage of all the application's data objects.


1 Answers

Your prefixes are wrong. For example:

[0].OneWeek.[0].projectId:1

should be:

[0].OneWeek[0].projectId:1

You have an extra dot (.). Read Phil Haack's article once again for the correct syntax when binding with lists.

You have the same problem with the gethours.[0] part.

I would recommend you using the standard editor templates conventions and avoid writing any foreach loops and dealing with indexes:

~/Views/Home/Index.cshtml:

@model List<WeekCollection>
@using(Html.BeginForm())
{ 
    @Html.EditorForModel()
    <input type="Submit" />
}

~/Views/Home/EditorTemplates/WeekCollection.cshtml:

@model WeekCollection
@Html.EditorFor(x => x.OneWeek)

~/Views/Home/EditorTemplates/Entry.cshtml:

@model Entry
...
like image 150
Darin Dimitrov Avatar answered Oct 08 '22 02:10

Darin Dimitrov