Stephan Olsen Stephan Olsen - 2 months ago 17
C# Question

C# For each loop in a a table?

I'm trying to display various information with the help of a for each loop.
I've created a for each loop, that iterates through a list of item. In this list there is another list of items.

As for now it's displayed like this:
enter image description here

My code is:

@foreach (Invoice invoice in ViewBag.Invoices)
{
<table>
<tr>
<th>Customer</th>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Total Price</th>
</tr>

@foreach (OrderItem orderItem in invoice.OrderItems)
{
<tr>
<td>@invoice.Customer.Firstname @invoice.Customer.Lastname</td>
<td>@orderItem.Product.Title </td>
<td>@orderItem.Quantity </td>
<td>@orderItem.Product.Price </td>
<td>@orderItem.TotalPrice</td>
</tr>
}

<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td class="border-top">@invoice.TotalPrice</td>
</tr>
</table>
}


However, I don't want it to display the customers name twice. And I don't want to have the customer on its own row. Therefore I tried to put the starting tag along with the customer outside of the foreach loop, and instead ending the foreach loop with a tag. So it'd look like this:

@foreach (Invoice invoice in ViewBag.Invoices)
{
<table>
<tr>
<th>Customer</th>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Total Price</th>
</tr>

<tr>
<td>@invoice.Customer.Firstname @invoice.Customer.Lastname</td>

@foreach (OrderItem orderItem in invoice.OrderItems)
{
<td>@orderItem.Product.Title </td>
<td>@orderItem.Quantity </td>
<td>@orderItem.Product.Price </td>
<td>@orderItem.TotalPrice</td>
</tr>
<tr>
}


<td></td>
<td></td>
<td></td>
<td></td>
<td class="border-top">@invoice.TotalPrice</td>
</tr>
</table>
}


UPDATED SOLUTION

I followed the wise words of @Ed Plunkett and initialized a local string to null. The I created an if/else statement to check if the previous customer has been set, and initialized the value of the previous customer in the end of the loop.

@{string prevCust = null; }

@foreach (Invoice invoice in ViewBag.Invoices)
{
<table>
<tr>
<th>Customer</th>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Total Price</th>
</tr>

@foreach (OrderItem orderItem in invoice.OrderItems)
{
<tr>
@if (prevCust != invoice.Customer.Firstname + invoice.Customer.Lastname)
{
<td>@invoice.Customer.Firstname @invoice.Customer.Lastname</td>
}
else
{
<td></td>
}

<td>@orderItem.Product.Title </td>
<td>@orderItem.Quantity </td>
<td>@orderItem.Product.Price </td>
<td>@orderItem.TotalPrice</td>
</tr>

prevCust = invoice.Customer.Firstname + invoice.Customer.Lastname;
}

<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td class="border-top">@invoice.TotalPrice</td>
</tr>
</table>
}

Answer

I'd do it caveman style: Just make a local variable String prevCustomerName, initialize to null, and update it at the end of the loop block. At the beginning of the loop block, if the new customer name is the same as prevCustomerName, don't insert it into the HTML for that row.

I enjoyed your original code with </tr>\n<tr> in the inner loop, but it took me a minute to figure out what you were doing, and Razor seems to be totally baffled. And you still need to ugly it up with a special case to add an empty cell on non-first rows. If you're stuck putting in an if either way, do the caveman.