Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC3 ModelBinding to a collection posted back with index gaps

I have a collection of objects on my Model that I'm rendering in a View by using EditFor function, and I have an EditorTemplate which is responsible for actually rendering each object.

@Html.EditorFor(model => model.MyObjects)

This has worked well for a while now, and when you check the html, my text boxes are prefixed with the model property, followed by the index of the collection they came from.

<input class="text-box single-line" id="MyObjects_2__SomeProperty" 
name="MyObjects[2].SomeProperty" type="Text" value="" />

However I've recently started using the ShowForEdit and ShowForDisplay properties in the model metadata for the collection, and in the first line of my editor template if the ShowForEdit is not true, I just skip it.

@if (!ViewData.ModelMetadata.ShowForEdit)
{
    return;
}

But because these are all indexed in the html, when I try to save this collection back to the viewmodel via a postback, it fails because of a reliance on the indexing numbers. Every item in the collection after the missing index is missing from my view model when I check it's value.

In this case it's actually my first item in the collection that I'm skipping since I don't want it to be visible on the edit view, but because of this when I postback the first index in the html is 1 (instead of 0 like it normally would be), but this is a problem when you try to save the changes. This is also a problem when altering the DOM using javascript.

Has anyone else encountered a problem with the default model binder's ability to read data posted back when one or more indexes in the html represented collection are not present?

Are there model binders that handle this problem?

like image 870
Nick Albrecht Avatar asked Nov 13 '22 19:11

Nick Albrecht


1 Answers

Ran into this issue recently and solved it by converting the List to a Dictionary<string, model> with GUIDs as the key.

@foreach (var index in Model.EmailAddresses.Keys)
{
    <label asp-for="@Model.EmailAddresses[index].Email">Email</label>
    <input asp-for="@Model.EmailAddresses[index].Email" type="text" />
}

This avoided having to include hidden inputs that map to the index value.

like image 140
nelowe Avatar answered Dec 18 '22 08:12

nelowe