My view model has the property:
public IEnumerable<string> Names { get; set; }
My view displays that information using a simple markup that renders to:
<div id="names">
<ul>
<li>Name1<img src="/delete.png"/></li>
<li>Name2<img src="/delete.png"/></li>
<li>Name3<img src="/delete.png"/></li>
</ul>
</div>
The image on each name allows you to delete the current name using some jQuery
$('#names li img').click(function () {
$(this).closest('li').remove();
});
I was hoping there would be some way to have my changes to the list from jQuery be reflected on my model. Could this behavior be accomplished through an MVC Editor Template?
I know I can create a hidden input with a delimited string and parse it out, but I want my view and my controller to have an easy time processing this list.
I thought if I added a name or an id to the ul element the model binder would be able to read the li elements and construct a list but that did not work.
Try adding a hidden input for the list item, using the name of the property (in your case “Names”), and the item’s index in square brackets. This definitely works:
The model binder needs some sort of context to decide how to bind complex types. By providing a hidden element with the correct name, it has enough context to decide that the item belongs in the Names property at index i. If you don’t include the index, it uses a finite set of items (meaning you can’t add or remove items from the list, and calling
.Add()or.Remove()will throw an exception).While I agree that the jQuery method will work, if no other part of your page is using JSON then why do a one off? The name on the hidden element is doing exactly the same thing, providing a name/value pair with its index. Only this way, the model binder does the work for you (for a small price of less-than-gorgeous view syntax). On the plus side, no javascript necessary to get this model binding properly.
If you’re using
IEnumerable<string>orICollection<string>, you have to use.ElementAt(i)like the above sample. If you’re using anIList<string>orstring[], you can use an indexer instead.EDIT: Solving the deletion problem
Create another view model for your strings, so you’ll have a
IEnumerable<NameViewModel> Names { get; set; }property on your actual view model (in place ofIEnumerable<string>). NameViewModel will look like this:Then, add a hidden element for
IsDeletedto the<li>. Remember that the model binder requires the proper name for context. After adding a property to the indexed name, the hidden inputs will look like this:In your jQuery delete code, find the hidden element and set the value to
True, and call.hide()on the list item. When you post the form to the server, your action method can figure out what should be deleted like this: