Reputation: 15111
I noticed a strange behavior in which there is inconsistent requirement of Model
prefix for asp.net core tag helpers below. asp-for
cannot accept Model
prefix but asp-items
must have Model
prefix. My head explodes.
@model ProblemVM
<select
asp-for="Problem.TagId"
asp-items="Model.Tags.ToSelectListItem(Model.Problem.TagId)"
/>
public class ProblemVM
{
public IEnumerable<Tag> Tags { get; set; }
public Problem Problem{ get; set; }
}
Related classes.
public abstract class ISelectListItemable
{
[Key]
public int Id { get; set; }
[Required]
public virtual string Name { get; set; }
}
public class Tag: ISelectListItemable
{
[Display(Name = "Tag Name")]
public override string Name { get; set; }
}
public class Problem : ISelectListItemable
{
[Display(Name = "Problem Name")]
public override string Name { get; set; }
public int TagId { get; set; }
[ForeignKey(nameof(TagId))]
public virtual Tag Tag { get; set; }
}
public static IEnumerable<SelectListItem> ToSelectListItem<T>(this IEnumerable<T> items, int selectedValue)
where T : ISelectListItemable
{
return from item in items
select new SelectListItem
{
Text = item.Name,
Value = item.Id.ToString(),
Selected = item.Id.Equals(selectedValue)
};
}
What is the rule of using Model
prefix for tag helpers?
Upvotes: 0
Views: 279
Reputation: 239380
It's about the actual type of the property the attribute of the tag helper corresponds to. The asp-for
attribute maps to a For
property on the built-in tag helpers which is typed as ModelExpression
. So, it literally is looking for an expression relative to the model of the view.
The asp-items
attribute, on the other hand is typed as IEnumerable<SelectListItem>
, and thus literally needs a concrete value, not just an expression. The fact that it just so happens to be coming from a prop on your model is inconsequential. The value could come from ViewData
, or be satisfied directly inline.
There are certain situations, though, when you still need to include Model
for an attribute like asp-for
. This is generally when your model itself is a list, dictionary, etc. and you need to index. You can't just add something like [i].Foo
as an expression, so in that case you would do @Model[i].Foo
.
Upvotes: 2
Reputation: 40958
The documentation does say that:
The
asp-for
attribute value is a special case and doesn't require a Model prefix, the other Tag Helper attributes do (such asasp-items
)
The reason I see is that asp-for
will always be from your model. But asp-items
can be any collection. It doesn't have to be from your model. So if you do want it to be from your model, you need to tell it that.
Upvotes: 1