Reputation: 1964
I'm working on a view that presents all the records of class (Machine
) where some of their properties could be updated.
For this, the view is working with an IEnumerable. These are the Get and Post methods:
Get:
public async Task<IActionResult> Test()
{
PopulateMachineTypeDropDownListStore();
return View(await _context.Machines.AsNoTracking().ToListAsync());
}
Post:
[HttpPost, ActionName("Test")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> TestPost(int id, [Bind("Id,StoreID,PUnit,Status")] Machine machine)
{
if (id != machine.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(machine);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!MachineExists(machine.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction("Index");
}
return View(machine);}
The problem is that the class sent to the Post Action is null (almost all their fields are zero or null except for the Id)
public async Task<IActionResult> TestPost(int id, [Bind("Id,StoreID,PUnit,Status")] Machine machine)
Question: So, I don't know how to correct this. Could there be something missing in the view?
@model IEnumerable<Application.Models.Machine>
@{
ViewData["Title"] = "Test";
}
@foreach (var item in Model)
{
<form asp-action="Test" asp-route-id="@item.Id" method="post">
<table class="table">
<tbody>
<tr>
<td>
<input type="hidden" asp-for="@item.Id" />
<div class="form-group">
<div class="col-md-10">
<input asp-for="@item.MchName" readonly class="form-control" />
<span asp-validation-for="@item.MchName" class="text-danger"></span>
</div>
</div>
</td>
<td>
<div class="form-group">
<div class="col-md-10">
<select asp-for="@item.StoreID" class="form-control" asp-items="ViewBag.StoreID">
</select>
<span asp-validation-for="@item.StoreID" class="text-danger"></span>
</div>
</div>
</td>
<td>
<div class="form-group">
<div class="col-md-10">
<input type="number" max="10" step=".1" asp-for="@item.PUnit" class="form-control" />
<span asp-validation-for="@item.PUnit" class="text-danger"></span>
</div>
</div>
</td>
<td>
<div class="form-group">
<div class="col-md-10">
<select name="Status" asp-for="@item.Status" class="form-control">
<option value="0">Operativo</option>
<option value="1">Nuevo Item</option>
<option value="2">Reparación</option>
</select>
<span asp-validation-for="@item.Status" class="text-danger"></span>
</div>
</div>
</td>
<td>
<input id="submit-data" type="submit" value="Update" class="btn btn-default" />
</td>
</tr>
</tbody>
</table>
</form>}
Thanks in advance
Upvotes: 0
Views: 60
Reputation: 2172
Because the ModelBinder uses naming conventions for binding, try renaming the machine
parameter of the TestPost()
method to item
.
public async Task<IActionResult> TestPost(
int id, [Bind("Id, StoreID, PUnit,Status")] Machine item)
{
//...
}
Alternatively, in your View, you could rename the item
variable to machine
, so it matches the expected parameter name:
@foreach (var machine in Model)
{ ... }
The docs describe this summarily:
Model binding looks for the pattern parameter_name.property_name to bind values to properties
Lastly, leave out the name
attribute in your Status dropdown, which would impede modelbinding. Just let asp-for
do the work:
<select asp-for="@item.Status" class="form-control">
I don't really know how you fill the Store dropdown, but you should at least see the PUnit
and Status
properties being filled up this way.
Upvotes: 1