I have a list of items which I want to output in a razor view. Between each item I want to add a separator line, like this:
item1 | item2 | item3
The simplest way to loop through items is with a foreach:
@foreach(var item in Model.items){
<span>@item.Name</span> |
}
Unfortunately this adds an extra separator line at the end of the list. Is there a simple way to skip this last separator line?
You can use string.Join
:
@Html.Raw(string.Join("|", model.Items.Select(s => string.Format("<span>{0}</span>", s.Name))))
Using string.Join
negates the need to check for the last item.
You can mix this with a Razor @helper
method for more complex markup:
@helper ComplexMarkup(ItemType item)
{
<span>@item.Name</span>
}
@Html.Raw(string.Join("|", model.Items.Select(s => ComplexMarkup(s))))
You could even create a helper method to abstract the Html.Raw()
and string.Join()
calls:
public static HtmlString LoopWithSeparator
(this HtmlHelper helper, string separator, IEnumerable<object> items)
{
return new HtmlString
(helper.Raw(string.Join(separator, items)).ToHtmlString());
}
Usage:
@Html.LoopWithSeparator("|", model.Items.Select(s => ComplexMarkup(s)))
Combining the other answers here with this article on inline templates, I came up with this helper method, which can be put in an extension class:
public static HelperResult Join<T>(this IEnumerable<T> list, Func<T, HelperResult> template, Func<T, HelperResult> separator)
{
var first = true;
var result = new HelperResult(writer =>
{
foreach (var item in list)
{
if (first == false)
separator(item).WriteTo(writer);
first = false;
template(item).WriteTo(writer);
}
});
return result;
}
The way to use it would then be
@Model.ListOfItems.Join(
@<a href="@item.Href">
@item.Name
</a>,
@<text> | </text>)
This supports html in both the items and the separator.
Not sure if this is the simplest way, or if these is a more elegant way, but you could do something like;
@foreach ( var item in Model.items){
<span>@item.Name</span> @(Model.items[Model.items.Count - 1] != item ? "|" : "")
}
So you are basically checking to see if the item
is the last item in the list.
Not tried this code sample, so you might need to tweek it.
Keep a counter variable and inside the loop and check whether it is the last item or not.
@{ int counter=0; }
@foreach(var item in Model.items){
counter++;
<span>@item.Name</span>
if(counter<Model.Items.Count)
{
@Html.Raw("|")
}
}
and the short version is
@{ int counter=0; }
@foreach(var item in Model.items){
counter++;
<span>@item.Name</span> @(counter< Model.items.Count?"|":"")
}