I'm model binding to a list using this pattern , however when I post the form the IList is always null.
I've successfully used this pattern before. This time it's a little different from what I've done in the past, because the fields are generated in a sub-loop. Not sure if that's why it's not working. I've done a lot of trial & error, so I'm hoping that someone can see what I'm doing wrong:
@model Collect.ViewModels.JobWorker
@{
ViewBag.Title = $"{Model.Job.Name} - Workers";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>@ViewBag.Title</h2>
@using (Html.BeginForm("Update", "Workers"))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model => Model.JobId)
int z = 0;
for (int x = 0; x < Model.WorkPeriods.Count; x++)
{
<h3>@Model.WorkPeriods[x].StartDate.toIsoDateString() through @Model.WorkPeriods[x].EndDate.toIsoDateString()</h3>
<div style="display: flex; flex-wrap: wrap;">
@for (int y = 1; y <= Model.Job.MaximumNumber; y++)
{
<div class="panel panel-primary panel-info-1" >
<div class="panel-heading">
<span class="fa fa-clock-o"></span> Opening @Model.Workers[z].OpeningNumber
</div>
<div class="panel-body">
@Html.DropDownListFor(model => Model.Workers[z].PersonId,
new SelectList(Model.People, "PersonId", "Name"),
htmlAttributes: new { @class = "form-control" })
</div>
</div>
@Html.HiddenFor(model => Model.Workers[z].Id);
@Html.HiddenFor(model => Model.Workers[z].JobId);
@Html.HiddenFor(model => Model.Workers[z].WorkerId);
@Html.HiddenFor(model => Model.Workers[z].OpeningNumber);
@Html.HiddenFor(model => Model.Workers[z].StartDate);
@Html.HiddenFor(model => Model.Workers[z].EndDate);
z++;
}
<div class="panel-info-1" >
<button type="submit" value="Update" class="btn btn-default">Update</button>
</div>
</div>
}
}
<div>
@Html.ActionLink("Back to Jobs", "Index", "Jobs")
</div>
public class JobWorker
{
public byte JobId { get; set; }
public Job Job { get; set; }
public List<Person2> People { get; set; }
public List<WorkPeriod> WorkPeriods { get; set; }
public IList<Dto.Worker> Workers { get; set; }
}
public class Worker
{
public Worker(byte id)
{
Id = id;
}
[Key]
public byte Id { get; set; }
public int? WorkerId { get; set; }
public int? PersonId { get; set; }
public byte JobId { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
public byte OpeningNumber { get; set; }
}
public ActionResult Index(int? Id)
{
var jobEnt = db.Jobs.Where(x => x.JobId == Id).FirstOrDefault();
var jobWorker = new JobWorker()
{
JobId = jobEnt.JobId,
Job = Mapper.Map<Ent.Job, Mod.Job>(jobEnt),
WorkPeriods = new List<WorkPeriod> { startPeriod },
Workers = new List<Dto.Worker>(),
People = db.People.ToList()
};
// business logic to populate WorkPeriods and Workers here.
return View(jobWorker);
}
<form action="/Workers/Update" method="post">
<input data-val="true" data-val-number="The field JobId must be a number." data-val-required="The JobId field is required."
id="JobId" name="JobId" type="hidden" value="7" />
<h3>2018-05-01 through 2018-05-31</h3>
<div style="display: flex; flex-wrap: wrap;">
<div class="panel panel-primary">
<div class="panel-heading">
<span class="fa fa-clock-o"></span> Opening 1
</div>
<div class="panel-body">
<select class="form-control" data-val="true" data-val-number="The field PersonId must be a number." id="Workers_0__PersonId"
name="Workers[0].PersonId">
<option value=""></option>
<option value="1">Person 1</option>
<option value="2">Person 2</option>
</select>
</div>
</div>
<input data-val="true" data-val-number="The field JobId must be a number." data-val-required="The JobId field is required."
id="Workers_0__JobId" name="Workers[0].JobId" type="hidden" value="7" />
<input data-val="true" data-val-number="The field WorkerId must be a number." id="Workers_0__WorkerId" name="Workers[0].WorkerId"
type="hidden" value="" />
<input data-val="true" data-val-number="The field OpeningNumber must be a number." data-val-required="The OpeningNumber field is required."
id="Workers_0__OpeningNumber" name="Workers[0].OpeningNumber" type="hidden" value="1" />
<input id="Workers_0__StartDate" name="Workers[0].StartDate" type="hidden" value="2018-05-01" />
<input id="Workers_0__EndDate" name="Workers[0].EndDate" type="hidden" value="2018-05-31" />
<div class="panel panel-primary" style="width: 400px; margin: 20px;">
<div class="panel-heading">
<span class="fa fa-clock-o"></span> Opening 2
</div>
<div class="panel-body">
<select class="form-control" data-val="true" data-val-number="The field PersonId must be a number." id="Workers_1__PersonId"
name="Workers[1].PersonId">
<option value=""></option>
<option value="1">Person 1</option>
<option value="2">Person 2</option>
</select>
</div>
</div>
<input data-val="true" data-val-number="The field JobId must be a number." data-val-required="The JobId field is required."
id="Workers_1__JobId" name="Workers[1].JobId" type="hidden" value="7" />
<input data-val="true" data-val-number="The field WorkerId must be a number." id="Workers_1__WorkerId" name="Workers[1].WorkerId"
type="hidden" value="" />
<input data-val="true" data-val-number="The field OpeningNumber must be a number." data-val-required="The OpeningNumber field is required."
id="Workers_1__OpeningNumber" name="Workers[1].OpeningNumber" type="hidden" value="2" />
<input id="Workers_1__StartDate" name="Workers[1].StartDate" type="hidden" value="2018-05-01" />
<input id="Workers_1__EndDate" name="Workers[1].EndDate" type="hidden" value="2018-05-31" />
<div style="width: 400px; margin: 20px;">
<button type="submit" value="Update" class="btn btn-default">Update</button>
</div>
</div>
</form>
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Update(byte JobId, IList<Dto.Worker> newWorkers)
{
// newWorkers is always null
// logic to update is here
return RedirectToAction("Index", "Jobs");
}
Based on the model used in the view,
@model Collect.ViewModels.JobWorker
The Update
action is expecting the wrong model, which is why it is not being converted by the model binder.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Update(byte JobId, JobWorker model) {
If(ModelState.IsValid) {
IList<Dto.Worker> newWorkers = model.Workers;
// logic to update is here
return RedirectToAction("Index", "Jobs");
}
return View(model);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.