tony09uk tony09uk - 4 months ago 48
Javascript Question

ASP MVC passing non-sequential items

I have a view model containing

public List<Room> Rooms { get; set; }
Rooms contains a
List<BL.Image> Images
. In my view I loop through the room and display each image.

for (int i = 0; i < Model.Rooms.Count; i++)
{
@for (var ii = 0; ii < Model.Rooms[i].Images.Count; ii++)
{
<div class="slide">
<img class="pic panel" src="@Url.Content(Model.Rooms[i].Images.ToList()[ii].Path)" />
@{ ViewBag.Imageindex = "Rooms[" + i + "].Images[" + ii + "].Index"; }
<input type="hidden" name="@ViewBag.ImageIndex" value="@Html.Raw(ii)" />
@*also tried<input type="hidden" name="@ViewBag.ImageIndex" value="" />also tried*@

@Html.HiddenFor(m => Model.Rooms[i].Images.ToList()[ii].ImageID, new { Name = "Rooms[" + i + "].Images[" + ii + "].ImageID" })
@Html.HiddenFor(m => Model.Rooms[i].Images.ToList()[ii].Path, new { Name = "Rooms[" + i + "].Images[" + ii + "].Path" })
<div class="snipit">
<img class="hoverpic panel" src="http://findicons.com/files/icons/99/office/128/delete.png" width="40" height="40" />
</div>
</div>
}
}


Images can be added or deleted by the user but if an image gets deleted, when the form is submitted only images before the deleted images are recognised e.g.


  • image 1, image 2, image 3, image 4 are displayed

  • image 3 get deleted

  • when the form is submitted only images 1 and 2 are recognised.



One of the questioned I reviewed to solve this issue was this one and I seem to be doing the same thing. The question also links to a Blog Post in this - near the end it covers non-sequential indices


Non-Sequential Indices
... what happens when you can’t guarantee that the submitted values will maintain a sequential index? For example, suppose you want to allow deleting rows before submitting a list of books via JavaScript.
The good news is that by introducing an extra hidden input, you can allow for arbitrary indices. In the example below, we provide a hidden input with the .Index suffix for each item we need to bind to the list. The name of each of these hidden inputs are the same ... this will give the model binder a nice collection of indices to look for when binding to the list.


<form method="post" action="/Home/Create">

<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />

<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />

<input type="hidden" name="products.Index" value="caliente" />
<input type="text" name="products[caliente].Name" value="Salsa" />
<input type="text" name="products[caliente].Price" value="1.23" />

<input type="submit" />





Unfortunately, we don’t have a helper for generating these hidden inputs.


What am I doing wrong?

Answer

You need 2 hidden inputs for the collection indexers with names Rooms.Index and Rooms[i].Images.Index. In addition, do not attempt to change the name attributes generated by the HtmlHelper methods. Your code should be

for (int i = 0; i < Model.Rooms.Count; i++)
{
    <input type="hidden" name="Rooms.Index" value="@i" /> // outer indexer
    @for (var ii = 0; ii < Model.Rooms[i].Images.Count; ii++)
    {
        <input type="hidden" name="Rooms[@i].Images.Index" value="@ii" /> // inner indexer
        <div class="slide">
            <img class="pic panel" src="@Url.Content(Model.Rooms[i].Images.ToList()[ii].Path)" />
            @Html.HiddenFor(m => Model.Rooms[i].Images[ii].ImageID)
            @Html.HiddenFor(m => Model.Rooms[i].Images[ii].Path)
            <div class="snipit">
                <img class="hoverpic panel" src="http://findicons.com/files/icons/99/office/128/delete.png" width="40" height="40" />
            </div>
        </div>
    }
}