I am trying to loop through all the elements retruned from getElementsByTagName("input")
using forEach. Any ideas why this does not work in FF, Chrome or IE?
<html>
<head>
</head>
<body>
<input type="text" value="" />
<input type="text" value="" />
<script>
function ShowResults(value, index, ar) {
alert(index);
}
var input = document.getElementsByTagName("input");
alert(input.length);
input.forEach(ShowResults);
</script>
</body>
</html>
You need to convert the nodelist to array with this:
<html>
<head>
</head>
<body>
<input type="text" value="" />
<input type="text" value="" />
<script>
function ShowResults(value, index, ar) {
alert(index);
}
var input = document.getElementsByTagName("input");
var inputList = Array.prototype.slice.call(input);
alert(inputList.length);
inputList.forEach(ShowResults);
</script>
</body>
</html>
or use for loop.
for(i = 0;i < input.length; i++)
{
ShowResults(input[i].value);
}
and change ShowResults function to:
function ShowResults(value) {
alert(value);
}
Yay, ES6:
const children = [...parent.getElementsByTagName('tag')];
children.forEach((child) => { /* Do something; */ });
Because input
is not an array, it's HTMLCollection
Use a for
loop would be better.
And since HTMLCollection
s are array-like objects you can call
Array#forEach
on it like this
Array.prototype.forEach.call(input, ShowResults);
It's becauseinput is html collection. html collection don't have forEach.
you can easily conver it to array by Array.prototype.slice
example:
function ShowResults(value, index, ar) {
alert(index);
}
var input = document.getElementsByTagName("input");
alert(input.length);
input = Array.prototype.slice.call(input)
input.forEach(ShowResults);
The reason, this does not work is because 'getElementsByTagName' returns an array - like Object rather than an actual array. In case you are not aware, here's how both of them look like :-
var realArray = ['a', 'b', 'c'];
var arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
Thus, since Array-like objects inherit from 'Object.prototype' instead of 'Array.prototype', this means that Array-like Objects can't access common Array prototype methods like forEach(), push(), map(), filter(), and slice().
Hope that helps!
getElementsByTagName
returns an HTMLCollection
, which do not have a forEach
method. But, there's a simple tweak that will allow you to iterate with forEach
without creating an intermediate array: use querySelectorAll
instead. querySelectorAll
returns a NodeList
, and modern browsers have a NodeList.prototype.forEach
method:
document.querySelectorAll('input')
.forEach((input) => {
console.log(input.value);
});
<input type="text" value="foo">
<input type="text" value="bar">
Another benefit to using querySelectorAll
is that it accepts comma-separated query strings, which are far more flexible and precise than just tag names. For example, the query string
.container1 > span, .container2 > span
will only match span
s which are children of elements with a class of container1
or container2
:
document.querySelectorAll('.container1 > span, .container2 > span')
.forEach((span) => {
span.classList.add('highlight');
});
.highlight {
background-color: yellow;
}
<div class="container1">
<span>foo</span>
<span>bar</span>
</div>
<div class="container2">
<span>baz</span>
</div>
<div class="container3">
<span>buzz</span>
</div>
If you want to use NodeList.prototype.forEach
on ancient browsers that do not have the method built-in, simply add a polyfill. The following snippet will work on IE11:
// Polyfill:
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = function(callback, thisArg) {
thisArg = thisArg || window;
for (var i = 0; i < this.length; i++) {
callback.call(thisArg, this[i], i, this);
}
};
}
// Main code:
document.querySelectorAll('.container1 > span, .container2 > span')
.forEach(function(span) {
span.classList.add('highlight');
});
.highlight {
background-color: yellow;
}
<div class="container1">
<span>foo</span>
<span>bar</span>
</div>
<div class="container2">
<span>baz</span>
</div>
<div class="container3">
<span>buzz</span>
</div>
HTMLCollections doesn't have the same methods as arrays. You can check this thing by tiping this in the javascript console of your browser.
var elements = document.getElementsByClassName('some-class');
'forEach' in elements;
And the console will return true
if elements
(in this case) has a method called forEach
to call.
In ES6 you can use the spread
operator to convert an HtmlCollection to an Array. see this question Why can't I use Array.forEach on a collection of Javascript elements?
input = [...input]
input.forEach(ShowResults)
I did this:
HTMLCollection.prototype.map = Array.prototype.map;
You can now use map on every HTMLCollection
.
document.getElementsByTagName("input").map(
input => console.log(input)
);
来源:https://stackoverflow.com/questions/19324700/javascript-loop-through-all-the-elements-returned-from-getelementsbytagname