How to check the last element of a foreach and apply an action

I have a "foreach" in a table that adds multiple items to a list, so the added items don't get mixed up I added a "|" however I wanted this bar not to appear for the last item added.

How do I select the last item in the "foreach" and hide the bar?

-Image List:

enter image description here

<td style="text-align: center;">
   @if (string.IsNullOrWhiteSpace(Model.ListTipoPenal.SingleOrDefault(i => i.Value == item.COD_TIPO_PENAL_PRINCIPAL.ToString())?.Text))
   {
    <span> NCI - Não Consta Informação </span>
   }
   else
   {
      foreach (var tipoPenal in item.TipoPenalList)
      {
       var listaString = Model.ListTipoPenal.SingleOrDefault(i => i.Value == tipoPenal.ToString())?.Text.Split("-");
       var listaCodigo = listaString[listaString.Length - 1].Split(" ", StringSplitOptions.RemoveEmptyEntries);
       if (listaString.Length == 3)
       {
         <span>@listaString[0] - @listaString[1] - @listaCodigo[0] <strong> @listaCodigo[1] </strong></span>
       }
       else
       {
         <span>@listaString[0] - @listaCodigo[0] <strong> @listaCodigo[1] 
         <span style="margin-left: 0.3em;margin-right: 0.3em;">|</span></strong></span>
       }
      }
   }
</td>

Upvotes: 1

Views: 2484

Answers (2)

KyleMit
KyleMit

Reputation: 29829

Easy, Inline Solution

Since it's slightly easier to identify the first element in a collection than the last

Instead of thinking of the bar as attached to the end of each item, except the last:

( item1 | ) ( item2 | ) ( item3 )

Think of it at the start of each item, except the first:

( item1 ) ( | item2 ) ( | item3 )

Which you can construct like this in a razor view:

@{
    var veggies = new [] { "Acai", "Bean", "Corn" };
    var first = true;
    foreach (var item in veggies)
    {
        if (!first)
        {
            @:<span> | </span>
        }
        @:<span> @item </span>
        first = false;
    }
}

Demo in .NET Fiddle

Reusable Function with String.Join

This is nearly identical to what we'd want to accomplish with String.Join, but we need to be able to support a raw HtmlString. For something a tad more extensible, you could create a utility function like this:

public static class Helpers
{
    public static IHtmlContent HtmlJoin(string separator, IEnumerable<object> items)
    {
        return new HtmlString(string.Join(separator, items));
    }
}

And then call it like this, passing in the html components as strings

var veggies = new [] { "Acai", "Bean", "Corn" };
@Helpers.HtmlJoin("<span> | </span>", veggies.Select(s => $"<span>{s}</span>"))

Reusable Function with Templated Razor delegates

If you have a big block of html, using strings has a lot of disadvantages. Instead, you can pass Templated Razor delegates to pass html snippets to the helper method like this:

public static class Helpers
{
    public static IHtmlContent HtmlJoin<T>(
        this IEnumerable<T> items,
        Func<T, IHtmlContent> separator,
        Func<T, IHtmlContent> itemTemplate)
    {
        var html = new HtmlContentBuilder();
        var first = true;

        foreach (var item in items)
        {
            if (!first) {
                html.AppendHtml(separator(item));
            }
            html.AppendHtml(itemTemplate(item));
            first = false;
        }

        return html;
    }
}

And then call like this - where @item is a special keyword that will be replaced with the contents of each item in the colleciton:

var veggies = new [] { "Acai", "Bean", "Corn" };
@veggies.HtmlJoin(@<span> | </span>, @<span>@item</span>) 

Further Reading

Upvotes: 0

mjb
mjb

Reputation: 136

inside your foreach try the following...

foreach (var tipoPenal in item.TipoPenalList)
{
   if (tipoPenal == item.TipoPenalList[item.TipoPenalList.Count - 1])
   {
      //this is the last one so do something different
   }
   else
   {
      //this is the rest so do what you normally do
   }
}

Upvotes: 1

Related Questions