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 to get 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 us modify the task and add the number of points and all the data to the table. It helps to display the user in the learner rankings:
-
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 hundreds of users? There are two ways:
- Bad: Write each user to their variable and add all users with the classic copy-and-paste method
- Good: create an array of
users
with all users inside it. Every user will be allocated their place in the array, making it convenient to add or delete users
const users = [
{
name: 'Hexlet',
surname: 'McCoderson',
login: 'hexlet-code',
scores: 1271
},
{
name: 'Layout',
surname: 'ODesign',
login: 'king-of-layout',
scores: 1100
},
]
We can use constructs called loops to traverse such an array. They go through each array element and get the information inside it.
Passing through the elements is called iteration. In the first iteration, you'll find Hexlet McCoderson's data. In the second iteration, you'll get Layout O'Design's data.
The main type of loop in Pug is the each in
, meaning for every an inside b:
- a is an arbitrary variable name available during iteration
- b is the array or object 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>
We changed one line: each user in users
. We read it as follows: for each user in the user's array and then output a tabular string with the data.
You can assign any name to the variable that will be accessible inside the loop. The name might not be user
, it could be people
or something else. You can choose any name that accurately represents the content.
If the code inside the loop is large, the naming 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 the array we search has at least one element. The array's content won't be output If there are no elements.
At this point, the user needs to know that there is no data, so they don't think there is an error with the page. It is what the `each else' is for. It is similar to the conditional construct but only works if 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 the value and the key in the object's location. For example, we can divide users into different groups: users, moderators, administrators, and so on. The object may have the following form in this case:
const users = {
admin: [
{
name: 'Hexlet',
surname: 'McCoderson',
},
],
moderator: [
{
name: 'Layout',
surname: 'ODesign',
},
{
name: 'Alex',
surname: 'Bossman',
},
],
}
The users
have several admin
and moderator
keys, which values are arrays of users. We can use a slightly modified each
loop syntax to output this list with job titles. We need to get the key name and the array in it:
each people, position in users
h2= position
ul
each user in people
li= user.name + ' ' + user.surname
We take several pieces of data 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: the data first and then the key.
This example uses a nested loop which 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 we do 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
When we work with Pug, we consider the each
cycle the main one, but it isn't the only one.
There are situations when we repeat the same actions several times. In this case, each
doesn't help, but there is another loop type – while
. It repeats a code section while 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 we use the while
, we should check that the condition changes to false sooner or later. It is a common mistake that can lead to an endless loop. In the last example, you should use count += 1;
to get an infinite loop. Without it, the value of count
will always be zero, meaning that the condition count < 5
will be true
at any point during compilation.
Additional assignment
The following kind of array goes into the 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>
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
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.