Mvc: Enhance collection properties on Razor, TagHelpers and MVC in general.

Created on 11 Nov 2015  路  7Comments  路  Source: aspnet/Mvc

public class CustomerViewModel {
    public string[] Phones { get; set; }
}

public IActionResult CreateCustomer(CustomerViewModel binding) {
    // ...
}

@Html.EditorFor( m => m.Phones)

The story on collection properties on razor views is not very good/friendly IMHO. Model binder does almost a good job but then neither TagHelpers or HtmlHelper "helps" ;)

I don't have any concrete suggestion. This is more like:

  1. Hey! I would love to see improvements in this area/scenario.
  2. Do you have any plan to make some improvements in this area/scenario ?
wontfix

All 7 comments

Could you tell us more about what specifically you think should be easier? /cc @dougbu who is the master of all things collection model binding.

@rynowak In #5085 for example, I would consider instead of having to write things like:

@for (int i = 0; i < Model.Images.Count; i++)
{
    <input type="hidden" asp-for="Images[i]" class="hidden-image" />
    Or
    @Html.HiddenFor(x=> x.Images[i])
}

Writing this:

<input type="hidden" asp-for="Images" class="hidden-image" />

@Bartmax did you mean something like that?

@gdoron not exactly what I was thinking. In your example there are very few room to customize.

My scenario was more like, for example, to use a collection in views, you must iterate with for (foreach doesn't work well with model binding) the collection, use the variable i on expression, etc.

I think a more flexible EditorFor-like tag helper will help.

something like:

<div asp-for="SomeCollection">
<label asp-for"Name">
<input asp-for="Name">
</div>

being Name a property of T inside the collection.

class ViewModel {
     IEnumerable<Some> SomeCollection {get;set;}
}
class Some {
     string Name {get; set;}
}

and be true to metadata like [Required] for the collection and the properties inside.

Right now I have two options:
1)

for (var i = 0; i < Model.SomeCollection.Length; i) {
var item = Model.SomeCollection[i];
<label asp-for"@item.Name">
<input asp-for="@item.Name">
}

this works ok for a root form, but when using a form inside you either have to use Prefix on controller or set the name manually on the html. (or controversially use foreach instead of for)

2)

Html.EditorFor(m=>m.SomeCollection) 

and create a EditorTemplate for this type. with the same issues as the previous example.

As I said, I don't have any concrete suggestion, just to point out that the experience/workflow right now is not fun. any improvement in this scenarios are welcome! :)

What does

for (var i = 0; i < Model.SomeCollection.Length; i) {
    var item = Model.SomeCollection[i];
    <label asp-for"@item.Name">
    <input asp-for="@item.Name">
}

output?

I'm not sure I understand your need (more specifically the part about the form inside).

Regarding my suggestion, do you see any drawback with it?
In case the binded property is a collection, the TagHelper should iterate over the items.

I will try to make a repro, because right now I have this issues in a very complex project.
but yes, there are drawbacks. I'll try to get something more concrete in a couple of days.

Another suggestion, please by all mean, finally save us from using an 8 years old hack for submitting Non-Sequential Indices.

That really should be much simpler.
If there is a gap, simply ignore it, I can't understand the reasoning behind the hidden index input.

Highly unlikely we'll deal with this directly. No plans to implement any of the suggestions in this issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dougbu picture dougbu  路  54Comments

NTaylorMullen picture NTaylorMullen  路  66Comments

sk29110 picture sk29110  路  33Comments

skyflyer picture skyflyer  路  40Comments

pranavkm picture pranavkm  路  35Comments