Register to get access to free programming courses with interactive exercises

Cycles HTML: Preprocessor Pug

In the lesson about conditional constructs, we used an object with data belonging to a user called Hexlet McCoderson:

const user = {
  name: 'Hexlet',
  surname: 'McCoderson',
  login: 'hexlet-code',
}

We used object.key when accessing the object fields. This is how we got data on the name and username of the user:

-
  const user = {
    name: 'Hexlet',
    surname: 'McCoderson',
    login: 'hexlet-code',
  }

section.user-profile
  p.name
    if user.name && user.surname
      | #{user.name} #{user.surname}
    else
      | #{user.login}

Let's modify the task a little bit and display the user in the learner rankings. We'll add the number of points and all the data to the table:

-
  const user = {
    name: 'Hexlet',
    surname: 'McCoderson',
    login: 'hexlet-code',
    scores: 1271
  }

section.container
  h2 User rating

  table
    thead
      tr
        th Name
        th Surname
        th Login
        th Scores
    tbody
      tr
        td= user.name
        td= user.surname
        td= user.login
        td= user.scores

This task is easy if you need to output a single user. But what if there are 2 users? 3? 100? There are two ways:

  1. Bad: Write each user to their own variable and add all users with the classic copy and paste method.
  2. Good: create an array of users with all users inside it. Thus, each user will be allocated their own place in the array, making it convenient to add or delete users.

Create a users array and add several different users to it:

const users = [
  {
    name: 'Hexlet',
    surname: 'McCoderson',
    login: 'hexlet-code',
    scores: 1271
  },
  {
    name: 'Layout',
    surname: 'ODesign',
    login: 'king-of-layout',
    scores: 1100
  },
]

Special constructs, loops, are used to traverse such an array. Their task is to go through each element of the array and get the information inside it. Passing through the elements is called iteration. During the first iteration, you'll find Hexlet McCoderson's data. During the second iteration, you'll get Layout O'Design's data.

The main type of loop in Pug is the each in. Essentially, it's for every “a” inside “b”. Where:

  • «a» is an arbitrary variable name that will be available during iteration.
  • «b» is the array or object from which you want to retrieve the data.
-
  const users = [
    {
      name: 'Hexlet',
      surname: 'McCoderson',
      login: 'hexlet-code',
      scores: 1271
    },
    {
      name: 'Layout',
      surname: 'ODesign',
      login: 'king-of-layout',
      scores: 1100
    },
  ]

section.container
  h2 User rating

  table
    thead
      tr
        th Name
        th Surname
        th Login
        th Scores
    tbody
      each user in users
        tr
          td= user.name
          td= user.surname
          td= user.login
          td= user.scores
<section class="container">
  <h2>User rating</h2>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Surname</th>
        <th>Login</th>
        <th>Scores</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Hexlet</td>
        <td>McCoderson</td>
        <td>hexlet-code</td>
        <td>1271</td>
      </tr>
      <tr>
        <td>Layout</td>
        <td>ODesign</td>
        <td>king-of-layout</td>
        <td>1100</td>
      </tr>
    </tbody>
  </table>
</section>

The main change was the addition of just one line: each user in users. We read it as follows: for each user in the users array and then output a tabular string with the data.


Important: you can assign any name to the variable that's accessible inside the loop. In the last example, this name may not be user, it could be people, or something else. Only you can choose that name, but try to choose a name that makes it clear what it represents. If the code inside the loop is large, it's the naming that determines how quickly and accurately the code will be interpreted by you or another developer.

You can read more in these articles:


You can't be sure that the array being searched has at least one element. If there are no elements, everything inside the array won't be output. At this point, it's important for the user to know that there's no information, so that they don't think there's an error with the page itself. This is what the each else is for. This is similar to the conditional construct, but only works when the array is empty.

- const users = []

section.container
  h2 User rating

  table
    thead
      tr
        th Name
        th Surname
        th Login
        th Scores
    tbody
      each user in users
        tr
          td= user.name
          td= user.surname
          td= user.login
          td= user.scores
      else
        tr
          td(colspan='4') No users
<section class="container">
  <h2>User rating</h2>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Surname</th>
        <th>Login</th>
        <th>Scores</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td colspan="4">No users</td>
      </tr>
    </tbody>
  </table>
</section>

The code from the last example is equivalent to the following:

- const users = []

if users.length
  each user in users
    tr
      td= user.name
      td= user.surname
      td= user.login
      td= user.scores
else
  tr
    td(colspan='4') No users

Nested loops and getting the object key

When going through an object, you sometimes have to get not only the value, but also the key where the object is located. For example, users can be divided into different groups: users, moderators, administrators, and so on. In this case, the object may have the following form:

const users = {
  admin: [
    {
      name: 'Hexlet',
      surname: 'McCoderson',
    },
  ],
  moderator: [
    {
      name: 'Layout',
      surname: 'ODesign',
    },
    {
      name: 'Alex',
      surname: 'Bossman',
    },
  ],
}

The users users has several keys: admin and moderator, whose values are arrays of users. A slightly modified each loop syntax is used to output this list with job titles. In it, you need to get the key name and the array.

each people, position in users
  h2= position
  ul
    each user in people
      li= user.name + ' ' + user.surname

Several data are taken from the users object: the people variable gets the value, and the position variable gets the key. Pay attention to the order of the variables: first the data and then the key.

This example uses a nested loop. This practice is standard for traversing big data. The first iteration in the top loop pulls the following data:

const people = [
  {
    name: 'Hexlet',
    surname: 'McCoderson',
  },
];

const position = 'admin';

The next step is to search through the people array, which is done in the same way as in the example above.

<h2>admin</h2>
<ul>
  <li>Hexlet McCoderson</li>
</ul>
<h2>moderator</h2>
<ul>
  <li>Layout ODesign</li>
  <li>Alex Bossman</li>
</ul>

While loop

The each cycle is rightly considered the main one when working with Pug, but it isn't the only one. There are situations when it's necessary to repeat the same actions several times. In this case, each doesn't help in any way, but in Pug there's another type of loop – while. Its task is to repeat a section of code as long as the condition is true. For example,

- let count = 0;

ul
  while count < 5
    li= "Hello, my number is " + count
    - count += 1;
<ul>
  <li>Hello, my number is 0</li>
  <li>Hello, my number is 1</li>
  <li>Hello, my number is 2</li>
  <li>Hello, my number is 3</li>
  <li>Hello, my number is 4</li>
</ul>

When using the while, it's important to make sure that the condition changes to false sooner or later. This is a common mistake that can lead to an endless loop. In the last example, to get an infinite loop, all you need to do is count += 1;. Without it, the value of count will always be zero, which means that the condition count < 5 will be true at any point during compilation.

Additional assignment

The following kind of array goes into icon.pug:

-
  const icons = {
    free: [
      {
        name: 'robot',
        url: './icons/robot.svg'
      },
      {
        name: 'hexlet',
        url: './icons/hexlet.svg'
      }
    ],
    premium: [
      {
        name: 'cat',
        url: './icons/premium/cat.svg'
      },
      {
        name: 'dog',
        url: './icons/premium/dog.svg'
      }
    ]
  };

Convert the data into the following template:

<h2>free</h2>
<ul>
  <li><a href="./icons/robot.svg">robot</a></li>
  <li><a href="./icons/hexlet.svg">hexlet</a></li>
</ul>
<h2>premium</h2>
<ul>
  <li><a href="./icons/premium/cat.svg">cat</a></li>
  <li><a href="./icons/premium/dog.svg">dog</a></li>
</ul>

Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs
Layout Designer icon
Profession
Under development beginner
Layout with the latest CSS standards
start anytime 5 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.