I have a data structure similar to the below; Simply I list of items, however, some items have nested items. I am calling the objects that have nested objects "sections" for the purposes of this question.
data = [
{title: "Section 1", items: [{id: "1"}, {id: "2"}]},
{title: "Section 2", items: [{id: "3"}, {id: "4"}]},
{id: "5"},
{id: "6"},
{id: "7"},
]
I am trying to loop through the items within the "sections" and then the remaining items however, I am getting the above error.
Attempt 1:
function addIsFavourite(favourites = [], sections) {
for (const section of sections) {
if ("items" in section) {
// Section has nested items
for (const item of section.items) {
item.isFavourite = favourites.includes(item.id);
}
} else {
// Section holds items directly
for (const item of section) {
item.isFavourite = favourites.includes(item.id);
}
}
}
return sections;
}
Returns error
[TypeError: iterator method is not callable]
Attempt 2:
function addIsFavourite(favourites = [], sections) {
if ("items" in sections) {
for (const section of sections) {
for (const item of section.items) {
item.isFavourite = favourites.includes(item.id);
}
}
} else {
for (const item of sections) {
item.isFavourite = favourites.includes(item.id);
}
}
return sections;
}
This only works on the first "section".
3
Answers
You’re trying to loop through each
section
object, which only contains anid
property and doesn’t have the iterator protocol. You don’t need a loop there as you’re already in the scope of each section.Neither do you need the
else
block as you’d probably want to check if the section itself is in thefavourites
array at any time.If you want loop through an object and use the iterator protocol, then you’d need to use the
Object.entries()
static method to convert an object to an array, which can be iterated over withfor...of
.The error you’re encountering indicates that you’re trying to iterate over an object that doesn’t have a callable iterator method. In your code, it seems like you’re assuming that section can be both an object and an array, but you need to handle these cases differently.
Here’s a revised version of your code that checks if section is an array before attempting to iterate over its items:
I hope this will work for you.
All you need to do is change the
else
block to only include the linesection.isFavourite = favourites.includes(section.id)
.You can also solve the problem with a one-liner like this:
data.flatMap(x => x.items ?? x)
will produce an array of all items at the first and second level (it will break if you have three levels of nesting, and you’d have to use recursion or a stack instead).Then, you can simply use
forEach
to setitem.isFavourite
where necessary.