Reputation: 20242
I have this Tampermonkey script:
// ==UserScript==
// @name Remove strong tags
// @namespace http://tampermonkey.net/
// @version 0.1
// @description remove answers
// @author You
// @match http://*/*
// @grant GM_log
// @run-at document-end
// ==/UserScript==
setTimeout((function() {
'use strict';
var allStrong = document.getElementsByTagName("strong");
GM_log(allStrong);
for (var i=0, max=allStrong.length; i < max; i++) {
var strong = allStrong.item(i);
GM_log(strong);
if(strong && strong.parentNode.tagName == "LI") {
strong.parentNode.appendChild(strong.firstChild);
strong.parentNode.removeChild(strong);
}
}
})(), 5000);
Out of 8 strong
tags that fit the criteria, it only replaces 4.
This is printed in the Chrome console.
The array when first printed has 8 elements, but then the last 4 elements are printed as undefined
.
Why is this happening?
I don't think the problem comes from the code being executed before the full page load, because I put a large timeout.
This is the page where I'm running it.
Upvotes: 0
Views: 341
Reputation: 6381
getElementsByTagName returns a so-called live NodeList
, not a static Array
- it means that it contains up-to-date results of your query.
So, after each of your iterations, one of the elements is removed as it is no longer <strong>
element.
You have 2 choices here:
NodeList
into normal Array
(eg. by using Array.from)NodeList
Upvotes: 4
Reputation: 6752
The first printout shows 8 elements because it's what it is at that point. But it is an HTMLCollection, and in the HTML DOM it is live; it is automatically updated when the underlying document is changed.
The for loop removes some of these <strong>
nodes as it goes (strong.parentNode.removeChild(strong);
), but only evaluates the length of the collection at the beginning (max=allStrong.length
). So it will still run 8 times, but by the time it reaches half, it iterates over nothing.
When you expand the first line of logs, Chrome evaluates your live HTMLCollection, which by that point only contains 4 elements, so it shows only 4. The little (i) at the end of the line tells you when this expression was evaluated.
If you want to see all this play out in real time, instead of putting it in a setTimeout
, I'd suggest adding the following statement in your code, wherever you want to start looking at it step by step:
debugger;
Upvotes: 2