Reputation: 135
I have a view that is displaying records on a table with checkboxes for the user to select and update. However, if I have 3 records in the table, Data[0], Data[1], Data[2] and I select only the checkbox for Data[0] and POST it to the controller, then when the screen is returned Data[1] checkbox now has the state of Data[0] that was submitted (true
). However the database shows the checkbox value is 0 (false) for Data[1]. My only guess is something with the model binding or I would need to persist the checkbox states some how.
Model
public class DrinkingWaterModel
{
//contains all properties of the FPDrinkingWater Entity
public List<FPDrinkingWater> Data { get; set; }
public AlertModel SuccessAlert { get; set; }
public AlertModel FailureAlert { get; set; }
}
GET Method
public async Task<ActionResult> UnverifiedDrinkingWaterLog(AlertModel
successAlert, AlertModel failureAlert)
{
//get unverified data from the db
var data = (from s in await Manager.Store.GetAllAsync<FPDrinkingWater>()
where s.Verified.Equals(false)
select s).ToList();
//fill the model
DrinkingWaterModel model = new DrinkingWaterModel
{
SuccessAlert = successAlert,
FailureAlert = failureAlert,
Data = data
};
return PartialView("_UnverifiedFPDrinkingWaterTable", model);
}
The View
@model MyApplication.Areas.FP.Models.DrinkingWaterModel
@{
Layout = null;
}
<div>
@Html.AntiForgeryToken()
<table id="UnverifiedDrinkingWaterTable" class="table table-hover">
<thead>
<tr>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().SID)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().Location)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().Replicate)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().CollectionDate)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().CollectionTime)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().Collectors)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().Clorinated)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().Comments)</th>
<th>@Html.LabelFor(m => m.Data.FirstOrDefault().Verified)</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Data.Count(); i++)
{
<tr>
@Html.HiddenFor(m => m.Data[i].Id)
@Html.HiddenFor(m => m.Data[i].SID)
<td>@Html.DisplayFor(m => m.Data[i].SID)</td>
@Html.HiddenFor(m => m.Data[i].Location)
<td>@Html.DisplayFor(m => m.Data[i].Location)</td>
@Html.HiddenFor(m => m.Data[i].Replicate)
<td>@Html.DisplayFor(m => m.Data[i].Replicate)</td>
@Html.HiddenFor(m => m.Data[i].CollectionDate)
<td>@Html.DisplayFor(m => m.Data[i].CollectionDate)</td>
@Html.HiddenFor(m => m.Data[i].CollectionTime)
<td>@Html.DisplayFor(m => m.Data[i].CollectionTime)</td>
@Html.HiddenFor(m => m.Data[i].Collectors)
<td>@Html.DisplayFor(m => m.Data[i].Collectors)</td>
@Html.HiddenFor(m => m.Data[i].Clorinated)
<td>@Html.DisplayFor(m => m.Data[i].Clorinated)</td>
@Html.HiddenFor(m => m.Data[i].Comments)
<td>@Html.DisplayFor(m => m.Data[i].Comments)</td>
<td>@Html.EditorFor(v => v.Data[i].Verified) </td>
</tr>
}
@if (Model.Data.Count() == 0)
{
<tr>
<td colspan="@Html.ColumnCount(9)"><em>No Drinking Water data to verify.</em></td>
</tr>
}
</tbody>
</table>
@if (verify)
{
<button type="submit" class="btn btn-primary" data-loading-text="Verifying...">Verify</button>
}
</div>
<script>
$(document).ready(function () {
makeDataTable('UnverifiedDrinkingWaterTable')
});
$('#RefreshDrinkingWater').click();
</script>
The POST method
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> VerifyDrinkingWater([System.Web.Http.FromBody] DrinkingWaterModel model)
{
var successAlert = new AlertModel();
var failureAlert = new AlertModel();
if (ModelState.IsValid)
{
List<string> successes = new List<string>();
List<string> failures = new List<string>();
foreach (var verifiable in model.Data)
{
if (verifiable.Verified != false)
{
verifiable.Verified = true;
verifiable.VerifiedDate = DateTime.Now;
verifiable.VerifiedBy = User.Identity.Name;
var result = await Manager.VerifyAsync(verifiable);
}
}
}
else
{
InvalidState(failureAlert);
}
//return the GET method to update and refresh the table
return await UnverifiedDrinkingWaterLog(successAlert, failureAlert);
}
Upvotes: 0
Views: 195
Reputation: 25551
The value isn't updating because it's being read by ModelState
and not the model. Check out some related questions to get a better idea of why this feature exists. The short version is that typically you only return the exact same page from a POST
if there is an error that needs to be corrected. By reading from the ModelState
you give the user the benefit of keeping their previous input.
Two options to resolve this problem:
ModelState.Clear();
in your HttpPost
action before returning the view. Personally I would not recommend this, but it is an option.ModelState
is valid, follow the Post -> Redirect -> Get pattern and call RedirectToAction
to your original HttpGet
method. If the ModelState
is not valid, then do what you're doing so you can show an error message and keep the user input.Upvotes: 1