Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Iteration

A loop repeats a piece of markup for every item of data. A café menu with twenty drinks does not need copying by hand — an array and one each are enough.

each over an array

A simple list of drinks in src/index.pug:

- const drinks = ["Espresso", "Cappuccino", "Hot chocolate"]
ul
  each drink in drinks
    li= drink

The lines under each repeat for every item, and the drink variable takes the array values in turn:

<ul>
  <li>Espresso</li>
  <li>Cappuccino</li>
  <li>Hot chocolate</li>
</ul>

The item index

A second variable after a comma receives the item index, starting from zero:

- const drinks = ["Espresso", "Cappuccino", "Hot chocolate"]
each drink, index in drinks
  p #{index + 1}. #{drink}

To start numbering from one, add 1 to the index:

<p>1. Espresso</p>
<p>2. Cappuccino</p>
<p>3. Hot chocolate</p>

A menu from data

In a real project the list comes from the build script. Pass an array of objects in build.js:

// build.js
const menu = [
  { name: "Espresso", price: 2 },
  { name: "Cappuccino", price: 3 },
  { name: "Hot chocolate", price: 3, soldOut: true },
];
 
const html = pug.renderFile("src/index.pug", { pretty: true, menu });

In src/index.pug each item's properties are read with a dot, and a sold-out drink gets a class:

ul.menu
  each item in menu
    li(class=item.soldOut ? "sold-out" : undefined)
      span.name= item.name
      span.price $#{item.price}

Three menu items; the hot chocolate has the sold-out class, which CSS can use to grey out the text:

<ul class="menu">
  <li><span class="name">Espresso</span><span class="price">$2</span></li>
  <li><span class="name">Cappuccino</span><span class="price">$3</span></li>
  <li class="sold-out"><span class="name">Hot chocolate</span><span class="price">$3</span></li>
</ul>

each over an object

When you loop over an object, the first variable receives the value and the second the key:

- const hours = { "Weekdays": "8:00–20:00", "Weekends": "10:00–18:00" }
dl
  each time, days in hours
    dt= days
    dd= time

The order of the variables is the reverse of what you might expect: value first, then key:

<dl>
  <dt>Weekdays</dt>
  <dd>8:00–20:00</dd>
  <dt>Weekends</dt>
  <dd>10:00–18:00</dd>
</dl>

An empty list

An else branch under each is output when the array has no items:

- const desserts = []
ul
  each dessert in desserts
    li= dessert
  else
    li No desserts yet.

Instead of an empty list the visitor sees a message:

<ul>
  <li>No desserts yet.</li>
</ul>

while

while repeats markup as long as a condition is true. You rarely need it — each is handier for lists:

- let n = 1
ul
  while n <= 3
    li Table #{n++}

Remember to change the variable inside the loop (n++ here), otherwise the loop never ends:

<ul>
  <li>Table 1</li>
  <li>Table 2</li>
  <li>Table 3</li>
</ul>

Common mistake

Outputting the whole object instead of its property:

ul
  each item in menu
    li= item

JavaScript turns an object into the string [object Object]:

<ul>
  <li>[object Object]</li>
  <li>[object Object]</li>
  <li>[object Object]</li>
</ul>

Use the property you need: item.name, item.price.

Thanks for reading!

Donate to the site — we work hard for you.