I have a model with the following
- ModelData: List<ModelData>
With ModelData has the following:
- Name (string)
- LanguageId: Guid
And ViewBag has the following:
- Languages: IEnumerable<Microsoft.AspNetCore.Mvc.Rendering.SelectListItem>
And the view has the following:
@for (int i = 0; i < Model.ModelData.Count; i++)
{
<div class="row">
<div class="form-group">
<label asp-for="ModelData[i].LanguageId" class="control-label"></label>
<select asp-for="ModelData[i].LanguageId" asp-items="@ViewBag.Languages" class="form-control">
</select>
<span asp-validation-for="ModelData[i].LanguageId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ModelData[i].Name" class="control-label"></label>
<input asp-for="ModelData[i].Name" class="form-control" />
<span asp-validation-for="ModelData[i].Name" class="text-danger"></span>
</div>
@if (i > 0)
{
<div class="col-md-4">
<div class="form-group">
<button name="RemoveDataItem" value="@i.ToString()" class="btn btn-primary">Remove</button>
</div>
</div>
}
</div>
}
<input type="submit" name="AddDataItem" value="Add Item" class="btn btn-primary" />
<input type="submit" value="Create" class="btn btn-primary" />
And the controller as the following:
public async Task<IActionResult> CreateAsync(CreateModel model, string addDataItem, string removeDataItem)
{
if (addDataItem != null)
{
await FillViewBag();
model.ModelData.Add(new ModelData());
return View(model);
}
else if (removeDataItem != null)
{
await FillViewBag();
int itemIndex = int.Parse(removeDataItem);
model.ModelData.RemoveAt(itemIndex);
return View(model);
}
if (!ModelState.IsValid)
{
await FillViewBag();
return View(model);
}
// Save
}
And it works great, however I have a problem as the following:
Let's say i pressed the add button two times so now I have three records on ModelData and I entered a value in all textboxes and selected values in all select list, then I pressed remove next to the second row, so it goes to the controller action, the method removes the data of the correct index, and returns to the view, so Now I should find two rows, first with the data that was entered in the first row, and second with the data that was entered in the third row (because the second row is removed), however, what actually happens is that I end up with the data of the first two rows not the first and the third.
Any help is appreciated considering I did the following:
- I validated that the item that is removed is the corect one (the second item), but the value is not bound correctly.
- I added this attribute to the textbox value="@Model.ModelData[i].Name", and it worked correctly but I think this is not the correct way to solve this issue, also I did not find a similar attribute for the select tag.
Edit:
- I also managed to add static Id for the input fields of each row, but it didn't help
Edit: The problem is that the index is changed after the second row is removed, so the index of the third row (originally was 2) became 1 after removing the second row, and thus it now has the previous name attribute of second row "ModelData[1].Name" and not "ModelData[2].Name" and I think this is the problem which makes the browser keeps the previous value of the second row
