Looping through a list in razor and adding a separ

2019-02-08 17:38发布

问题:

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?

回答1:

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)))


回答2:

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.



回答3:

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.



回答4:

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?"|":"")
 }