I am using .NET Core 3.0 to build a web application which contains an EditorTemplate for a list of values. This EditorTemplate is inside a PartialView. A PartialView is returned from my ActionMethod whenever I add or remove a record from the list.
The confusion is, whenever I remove a record from top/middle of the list, the EditorTemplate is messed up. Please check the images below.
Question 1: Why is the happening and how to resolve it?
Question 2: Why is value different when I use <input type="text" asp-for="FilterId" class="form-control" />
& <input type="text" value="@Model.FilterId" />
AdvancedFilterVM EditorTemplate
@model SSAQ.Web.ViewModels.AdvancedFilterVM
<tr>
<td>
<input type="text" asp-for="FilterId" class="form-control" />
</td>
<td>
@Html.TextBoxFor(m => m.FilterId, new { @class="form-control" })
</td>
<td>
<input type="text" value="@Model.FilterId" class="form-control" />
</td>
<td style="text-align:center;vertical-align:middle;">
<a href="#" class="deleteFilter" data-filterid="@Model.FilterId"><i style="font-size:20px;" class="fa fa-times"></i></a>
</td>
</tr>
_SurveyFilter PartialView
@model SSAQ.Web.ViewModels.SurveySubmissionViewModel
@if (Model.AdvancedFilter?.Any() == true)
{
<table class="table" id="tblFilter">
<thead>
<tr>
<th>Using asp-for=FilterId</th>
<th>Using @@Html.TextBoxFor(m => m.FilterId)</th>
<th>Using value=@@Model.FilterId</th>
<th> </th>
</tr>
</thead>
<tbody id="tblFilterSurvey">
@Html.EditorFor(m => m.AdvancedFilter)
</tbody>
</table>
}
JQuery to delete row
$('body').on('click', '.deleteFilter', function (e) {
e.preventDefault();
var filterId = $(this).data('filterid');
var formData = $("#formFilter").serializeArray();
formData.push({ name: 'filterId', value: filterId });
$.ajax({
type: 'POST',
context: this,
url: '@Url.Content("~/Survey/DeleteFilterRow")',
data: formData,
success: function (response) {
$('#filterTableDiv').html(response);
}
});
});
DeleteFilterRow action method
public IActionResult DeleteFilterRow(SurveySubmissionViewModel surveySubmissionVM, Guid filterIdToRemove)
{
surveySubmissionVM.AdvancedFilter.Remove(surveySubmissionVM.AdvancedFilter.Single(m => m.FilterId == filterIdToRemove));
return PartialView("_SurveyFilter", surveySubmissionVM);
}
I could reproduce the same issue. I thought it was caused by cache. But it is not. It really refreshes my knowledge: EditorFor
renders the template using ModelState prior to Model.
Clear the ModelState before rendering:
ModelState.Clear();
return PartialView("_SurveyFilter", surveySubmissionVM);
Quoted from MSDN Blog:
ASP.NET MVC assumes ... Therefore, the Html Helpers actually check in ModelState for the value to display in a field before they look in the Model. This enables them to redisplay erroneous data that was entered by the user, and a matching error message if needed.
There're also some threads online talking about this behavior online:
(Although they're all about ASP.NET, the theory applies for ASP.NET Core too)