How to limit forEach to work only on a certain area or list (such as a very certain ul or ol list)?

I am trying to loop through an element (ul list) list and delete all its sub-elements (li elements) which contain a certain special character (colon) but when limiting/focusing forEach() to just a certain list element that I want to work on.

I have tried adding listToWorkOn. just before listElements.forEach( (element) => {...} so I got:

const webPageToWorkOn = "https://www.example.com";
const listToWorkOn = document.querySelector(".special");
const [...listElements] = document.querySelectorAll("li");

if ( document.location.href == webPageToWorkOn ) {
    listToWorkOn.listElements.forEach( (element) => {
        if ( element.innerHTML.includes(':') ) {
            element.style.display = 'none';
        }
    })
};

But in console it brings the error:

Uncaught TypeError: Cannot read property ā€˜forEach’ of undefined

StackExchange sessions about this error are often antique and I didn’t find any alternative solution.

In great plea I ask for help from the JavaScript experts here.

okay, whoever gave you this line:

needs to be smacked over the head with a nerf bat.
Let’s… extract what you’re trying to do for a moment.

You want to walk across all child elements of an <ol> with class special.

const listElements = document.querySelectorAll(".special li");
listElements.forEach((element) => { ....

(If you want to be pedantic/specific, it would be ā€œol.special > liā€, but… unless you’ve got lists inside lists, this should work.)

2 Likes

I thank you for the explanation about to fix my code, indeed the following code, based on your example, worked:

const webPageToWorkOn = "https://www.example.com";
const listAndItsChildren = document.querySelectorAll(".special li");

if ( document.location.href == webPageToWorkOn ) {
    listAndItsChildren.forEach( (element) => {
        if ( element.innerHTML.includes(':') ) {
            element.style.display = 'none';
        }
    })
};
1 Like

And if I may (because you might be a moderator here of some sort) — with all niceness and respect to you I suggest to remove the comment about a hit in the head with a nerf bat. I don’t even recall where I found that but anyway I believe that just explaining the mistake would be enough (yes, I know you were kidding, it’s a matter of example to those who might not understand it).

If it’s any consolation, I found the banter about the nerf bat to have just the right amount of silliness that we expect around here. Right on target, one might say.

2 Likes

Something to keep in mind, in order to use yourVar.forEach() yourVar MUST be an array.

Also, when you chain properties you risk getting an ā€˜undefined’ value, especially if a query returns no results ( for example, if your list contained 0 LIs). In your specific case, listToWorkOn doesnt have the property listElements, so thats your error :wink:

Finally, the beauty of query selector all is that you can get a COLLECTION of elements via a CSS selector; but this means you must write your selector as specifically as possible, or you risk getting items outside your intended scope. As other people have pointed out you could use a more specific selector with document.querySelectorAll() such as ā€œ.special>liā€

Iin case you are actually targeting a specific instance of .special, you can also do: listElements = listToWorkOn.querySelectorAll("li"). Assuming, you don’t have nested list inside your .special. I think this is what you were originally trying to do and I find this handy, when you want to do a .querySelectorAll() dynamically.

Hope this clears things up for you.

Not quite true, as a NodeList (such as is returned by querySelectorAll) implements forEach.
It is true that NodeList is not an Array, but it is an Array-like, so it also qualifies to be put into Array.from() if you need to convert it to an actual array.

1 Like

Agreed. querySelectorAll is handy to get the elements, and when more than forEach is wanted (such as filter or map, or reduce, that’s where Array.from() makes things nice and easy, by giving easy access to filter/map/reduce methods.

var els = document.querySelectorAll(selector);
var resultingEls = Array.from(els).filter(desiredEls).map(transformEls);
1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.