web-dev-qa-db-fra.com

JavaScript: Parcourez tous les éléments renvoyés par getElementsByTagName

J'essaie de parcourir tous les éléments renvoyés par getElementsByTagName("input") à l'aide de forEach. Des idées pour lesquelles cela ne fonctionne pas dans FF, Chrome ou 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>
44
slayernoah

Vous devez convertir la liste de noeuds en tableau avec ceci:

<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>

ou utiliser pour la boucle.

for(i = 0;i < input.length; i++)
{
    ShowResults(input[i].value);
}

et remplacez la fonction ShowResults par:

function ShowResults(value) {
   alert(value);
}
68
Dvir

Oui, ES6:

const children = [...parent.getElementsByTagName('tag')];
children.forEach((child) => { /* Do something; */ });

MDN Doc pour Spread Operator (...)

37
jtheletter

Puisque input n’est pas un tableau, c’est HTMLCollection Utiliser une boucle for serait préférable.

Et puisque HTMLCollections sont des objets de type tableau, vous pouvez callArray#forEach dessus comme ça

Array.prototype.forEach.call(input, ShowResults);
8
grape_mao

C'est parce que l'entrée est une collection HTML. La collection HTML n'a pas forEach.

vous pouvez facilement le convertir en tableau par Array.prototype.slice

exemple:

function ShowResults(value, index, ar) {
            alert(index);
        }
        var input = document.getElementsByTagName("input");
        alert(input.length);
input = Array.prototype.slice.call(input)
        input.forEach(ShowResults);

http://jsfiddle.net/fPuKt/1/

5
Daniel Dykszak

La raison, cela ne fonctionne pas, c'est parce que 'getElementsByTagName' renvoie un objet semblable à un tableau plutôt qu'un tableau réel. Au cas où vous ne le sauriez pas, voici à quoi ressemblent les deux: -

var realArray = ['a', 'b', 'c'];
var arrayLike = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

Ainsi, comme les objets ressemblant à Array héritent de 'Object.prototype' au lieu de 'Array.prototype', cela signifie que les objets ressemblant à Array ne peuvent pas accéder au prototype Array commun. des méthodes telles que forEach (), Push (), map (), filter () et slice ().

J'espère que ça t'as aidé!

4
Naman Sancheti

getElementsByTagName renvoie un HTMLCollection, qui n'a pas de méthode forEach. Mais il existe un simple Tweak qui vous permettra d’itérer avec forEachsans créer un tableau intermédiaire: utilisez querySelectorAll à la place. querySelectorAll retourne un NodeList, et les navigateurs modernes ont un NodeList.prototype.forEach méthode:

document.querySelectorAll('input')
  .forEach((input) => {
    console.log(input.value);
  });
<input type="text" value="foo">
<input type="text" value="bar">

L’utilisation de querySelectorAll présente un autre avantage: elle accepte les chaînes de requête séparées par des virgules, qui sont beaucoup plus souples et précises que les noms de balises. Par exemple, la chaîne de requête

.container1 > span, .container2 > span

ne fera correspondre que spans qui sont des enfants d'éléments avec une classe de container1 ou 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>

Si vous voulez utiliser NodeList.prototype.forEach sur les anciens navigateurs n’ayant pas la méthode intégrée, ajoutez simplement un polyfill . L'extrait suivant fonctionnera sur 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>
3
CertainPerformance

HTMLCollections n'a pas les mêmes méthodes que les tableaux. Vous pouvez vérifier cette chose en la glissant dans la console javascript de votre navigateur.

var elements = document.getElementsByClassName('some-class');
'forEach' in elements;

Et la console retournera true si elements (dans ce cas) a une méthode appelée forEach à appeler.

2
Andrés Torres

Dans ES6, vous pouvez utiliser l'opérateur spread pour convertir une HtmlCollection en un tableau. voir cette question Pourquoi ne puis-je pas utiliser Array.forEach sur une collection d'éléments Javascript?

input = [...input]
input.forEach(ShowResults)
1
inostia

J'ai fait ça:

HTMLCollection.prototype.map = Array.prototype.map;

Vous pouvez maintenant utiliser la carte sur chaque HTMLCollection.

document.getElementsByTagName("input").map(
    input => console.log(input)
);
1
António Almeida