13.4. Iterating in a Template¶
Let’s revisit part of the non-efficient HTML from the introduction, where we hard-coded coffee options in a list.
1 2 3 4 5 6 | <ol>
<li>French Roast</li>
<li>Espresso</li>
<li>Kopi Luwak</li>
<li>Instant</li>
</ol>
|
If we want to add, remove, or edit the list items, we need to go in and change the individual tags, which is a poor use of our time. Fortunately, there is a way to streamline the process.
In C#, we use a foreach Loop to iterate through the items in a data collection.
foreach (type item in items) {
// Code to repeat...
}
Razor templates allow us to use a foreach
loop to display items in a
collection.
1 2 3 4 5 6 | <ol>
@foreach (type collectionItem in ViewBag.collectionProperty)
{
<li>@collectionItem</li>
}
</ol>
|
The
@foreach
loop is initiated inside of a list element (either<ol>
or<ul>
).ViewBag.collectionProperty
represents any collection that has been assigned as a property onViewBag
.collectionItem
represents an individual item or element within the collection.The
@
specifies the C# portion of the template.
We can think of this syntax as saying, “For each item within ViewBag’s property, ‘collectionProperty’, repeat this HTML tag, but use the current value of ‘collectionItem’.”
Let’s apply this new concept to the HTML coffee list example. Assume that we store each of
the coffee names as strings in a List
called ViewBag.coffeeOptions
.
1 2 3 4 5 6 | <ol>
@foreach (string coffeeType in ViewBag.coffeeOptions)
{
<li>@coffeeType</li>
}
</ol>
|
Some points to note:
coffeeOptions
is accessible to the template because it is a property of theViewBag
object.In the first pass through the loop,
coffeeType
takes the value of the first coffee name in thecoffeeOptions
list.@coffeeType
displays the value ofcoffeeType
in the view, so theli
element will show the first coffee name.Each successive iteration,
coffeeType
takes the next value in the list, and Razor adds a new<li></li>
element to display that data.
Warning
@foreach
creates one HTML tag for each item in a collection.
BE CAREFUL where you place it.
Consider the following Razor code:
1 2 3 4 5 6 7 8 9 | <div>
<h3>Coffee Types</h3>
@foreach (string coffeeType in ViewBag.coffeeTypes)
{
<ol>
<li>@coffeeType</li>
</ol>
}
</div>
|
The final HTML produced is one heading, 4 ordered lists, and 4 coffee names. When this view is rendered, each coffee type is labelled with “1”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <div>
<h3>Coffee Types</h3>
<ol>
<li>French Roast</li>
</ol>
<ol>
<li>Espresso</li>
</ol>
<ol>
<li>Kopi Luwak</li>
</ol>
<ol>
<li>Instant</li>
</ol>
</div>
|
13.4.1. Nested Loops¶
Assume you have a collection of different CoffeeShop
objects. Each
object contains a string field for name
and a field that is a list of
of the brews available, coffeeOptions
.
Below, we nest loops to display a list of the shop names and their brew options.
Sample Razor template:
1 2 3 4 5 6 7 8 9 10 11 12 | @foreach (var coffeeShop in ViewBag.coffeeShops)
{
@*Each shop name*@
<p>@coffeeShop.Name</p>
<ul>
@foreach(string coffeeType in coffeeShop.CoffeeOptions)
{
@*Each coffee type available*@
<li>@coffeeType</li>
}
</ul>
}
|
Sample HTML output:
1 2 3 4 5 6 7 8 9 10 11 | <p>Central Perk</p>
<ul>
<li>Espresso</li>
<li>Instant</li>
</ul>
<p>Brews Brothers</p>
<ul>
<li>French Roast</li>
<li>Kopi Luwak</li>
</ul>
|
Apart from the nested loops displayed above, here are some other items you may find useful to note from the example above.
Razor comments are seen on lines 3 and 8 in the first code block above. Comments in Razor are nested between
@*
and*@
. You may have noticed the comment block present on the top of a new view file.
ViewBag.coffeeShops
is a list ofCoffeeShop
objects but we’ve usedvar
on line 1 to type thecoffeeShop
item.In some limited circumstances, we can use the var keyword to implicitly type a variable. When this keyword is used, C# still assigns a type to
coffeeShop
through inference. It looks and sees that we are assigningcoffeeShop
to the value at the list index, which is aCoffeeShop
object. Thus,coffeeShop
is of typeCoffeeShop
.Alternatively, Razor does also allow us to import a custom class, such as
CoffeeShop
. If we wanted to do so, we could import the class or its namespace at the top of the template with a using statement.
Warning
We use var
above to simplify the example and focus on the loop action.
In general, we recommend that you avoid using var
while you are learning C#.
Even after you become more experienced with the language, you will still only
want to use it sparingly and in specific circumstances. Explicitly
declaring the type of your variables makes for more readable code, to name
only one benefit.
13.4.2. Check Your Understanding¶
Question
What is the HTML outcome you expect from the Razor code below?
1 2 3 4 5 6 7 8 9 | <div>
<h3>Coffee Types</h3>
<ol>
@foreach (string coffeeType in ViewBag.coffeeTypes)
{
<li>@coffeeType</li>
}
</ol>
</div>
|
One heading, 4 ordered lists, and 4 coffee names (each name labeled as “1”)?
One heading, one ordered list, and 4 coffee names (with the names labeled “1”, “2”, “3”…)?
4 headings, 4 ordered lists, and 4 coffee names (each name labeled as “1”)?
4 headings, 4 ordered lists, and 16 coffee names (with the names labeled “1”, “2”, “3”…)?
Question
What is the HTML outcome you expect from the Razor code below?
1 2 3 4 5 6 7 8 9 | @foreach (string coffeeType in ViewBag.coffeeTypes)
{
<div>
<h3>Coffee Types</h3>
<ol>
<li>@coffeeType</li>
</ol>
</div>
}
|
One heading, 4 ordered lists, and 4 coffee names (each name labeled as “1”)?
One heading, one ordered list, and 4 coffee names (with the names labeled “1”, “2”, “3”…)?
4 headings, 4 ordered lists, and 4 coffee names (each name labeled as “1”)?
4 headings, 4 ordered lists, and 16 coffee names (with the names labeled “1”, “2”, “3”…)?