Reputation: 2347
I am trying to add some text after @Html.DisplayFor() helper in ASP.net MVC 5 view, but can't get it to work.
My code:
@foreach (var item in Model.Changes)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Value)
</td>
<td>
@Html.DisplayFor(modelItem => item.Date)
</td>
<td>
@foreach (var tag in item.Tags)
{
@Html.DisplayFor(modelItem => tag.Name)
}
</td>
</tr>
}
The problem is the Tags IEnumerable. It renders like this:
I want to separate tags so that they are readable easily (eg. "Tag1, Tag2, ...") or with pipe sign (" | "). I guess this is easily done, but as I can't C#/ASP well I can't get it to work. Tried adding text just after @Html.DisplayFor(modelItem => tag.Name)
but this gives me compilation error.
If this changes anything, Tags are added with Tag-it.
Upvotes: 2
Views: 6558
Reputation: 2786
You should consider using display templates.
To create a display template you will need to add new view in Views/Shared/DisplayTemplates
folder. In your example you can create view named "Tags" that could look something like that:
@model IEnumerable<Tag>
@{
var tags = Model != null ? Model.ToList() : new List<Tag>();
var tagsCount = tags.Count;
}
@for (int i = 0; i < tagsCount; i++)
{
@tags[i].Name
if (i < tagsCount - 1)
{
<text> | </text>
}
}
And then in your main view:
@Html.DisplayFor(x => item.Tags, "Tags")
You can also think about making such code more generic and reusable. Views can't have generic models, so you can create a wrapper for that:
public interface IDisplayItem
{
dynamic Item { get; }
Func<string> DisplayValueFn { get; }
}
public class DisplayItem<T> : IDisplayItem
{
public T Item { get; set; }
dynamic IDisplayItem.Item
{
get { return Item; }
}
public Func<T, string> DisplayValueFn { get; set; }
Func<string> IDisplayItem.DisplayValueFn
{
get { return () => DisplayValueFn(Item); }
}
}
Then display template will look like that:
@model IEnumerable<IDisplayItem>
@{
var items = Model != null ? Model.ToList() : new List<IDisplayItem>();
var itemsCount = items.Count;
}
@for (int i = 0; i < itemsCount; i++)
{
@items[i].DisplayValueFn()
if (i < itemsCount - 1)
{
<text> | </text>
}
}
And you can show tags from your example this way:
var tags = item.Tags
.Select(tag => new DisplayItem<Tag>
{
Item = tag,
DisplayValueFn = x => x.Name
});
@Html.DisplayFor(x => tags, "Collection")
Upvotes: 0
Reputation: 566
Going further down the line. You can also do like this. If you want to apply css / modify dom element.
<span class="sometext">@Html.DisplayFor(modelItem => tag.Name) some text </span>
Upvotes: 0
Reputation: 4330
I would move the display logic to your model by creating a new property in your model:
@using System.Linq;
...
public TagDisplayText
{
get
{
return string.Join(", ", Tags.Select(x => x.Name));
}
}
and then call this property from your view:
<td>
@Html.DisplayFor(m => m.TagDisplayText)
</td>
Upvotes: 1
Reputation: 712
One solution could be:
<td>
@foreach (var tag in item.Tags)
{
@Html.DisplayFor(modelItem => tag.Name)<text>|</text>
}
</td>
Upvotes: 7