I’m working on a Library Express App and I’m using fake data to easily display the values on screen.
const PopularBooks = [
{
id: 1,
title: "Harry Potter",
characters: [
{
id: 1,
name: "Harry Potter",
},
{
id: 2,
name: "Hermione",
},
{
id: 3,
name: "Ron",
},
],
{
id: 2,
title: "Lord of the Rings",
characters: [
{
id: 4,
name: "Frodo",
},
{
id: 5,
name: "Legolas",
},
{
id: 6,
name: "Gandalf",
},
],
},
];
I’m able to display everything just fine except I’m having trouble getting character names to show.
<div class="description">
<h1><%= book.title %></h1>
</div>
</div>
<div class="data-m1">
<h4>Characters</h4>
<div class="characters">
<% for (let i = 1; i < 4; i++) { %>
<div class="portrait">
<img class="book-c" src="/images/book-c-1.png" alt="book" />
<p><%= book.characters[0].name %></p>
</div>
<% } %>
</div>
</div>
When I put <p><%= book.characters[0].name %></p> it shows Harry Potter three times. But when I change the [0] to [i] so that it will dynamically display everyone’s name, it gives me this error: Cannot read properties of undefined (reading 'name'). I’m wondering if there is a better way to map it out because I can’t seem to find any.
And here is how I got the value of book in case you’re wondering.
router.get("/books/:title", function (req, res, next) {
const bookId = parseInt(req.params.title);
const book = data.PopularBooks.find((book) => book.id === bookId);
res.render("books", { book });
});
>Solution :
As mentioned in Mamun@‘s answer, you have an off-by-one issue in your loop, however, instead of fixing that, I would instead encourage you to use forEach, so that you or anyone else who reads the code don’t have to worry about handling indexes at all and therefore improving readability since it focuses on what you want to do with each element rather than how to iterate through them:
<div class="characters">
<% book.characters.forEach(character => { %>
<div class="portrait">
<img class="book-c" src="/images/book-c-1.png" alt="book" />
<p><%= character.name %></p>
</div>
<% }); %>
</div>