Noté un problema extraño al usar Element.children y parece que no encuentro una buena solución.
Tome este HTML:
<form> <input name="hi"> <input name="bye"> </form>
Y este JS
const formElement = document.querySelector('form'); for (let i = 0; i < formElement.children.length; i++) { console.log(formElement.children[i].name); }
La consola imprime lo siguiente, como era de esperar:
"hi" "bye"
Ahora, agreguemos un campo de entrada con name="children"
<form> <input name="hi"> <input name="bye"> <input name="children"> </form>
La consola no imprime nada.
formElement.children
devuelve una HTMLCollection . En una colección HTML, puede acceder a los elementos secundarios a través de un índice o directamente mediante el atributo de nombre del elemento al que intenta apuntar.
Entonces, para obtener el elemento "hola" , podría decir formElement.children[0]
o formElement.hi
.
Sin embargo, cuando hay un elemento con el nombre "children"
dentro de la colección, formElement.children
devolverá el elemento con nombre="niños", y ya no hay forma de recorrer todos los elementos.
Esa es mi pregunta. Sé que simplemente no puedo usar el nombre "niños" y elegir otra cosa en su lugar, pero seguramente debe haber una manera de hacer que esto funcione.
Aquí hay un bolígrafo para ilustrar el problema: https://codepen.io/pwkip/pen/XWVoXVE
EDITAR:
esto parece estar relacionado con el hecho de que formElement es un <form>
. Cuando lo cambio a un <div>
, las cosas funcionan. Entonces, supongo que la pregunta se reduce a esto: ¿cómo convierto un elemento HTMLFormElement en un elemento HTML normal?
Esto se debe a que, por razones históricas bastante desafortunadas, HTMLFormElement tiene un captador de propiedad con nombre , que devolverá los elementos secundarios <input>
que tienen su valor de propiedad .name
o .id
establecido en el nombre dado. En realidad es más complejo que eso, pero no tan interesante.
En mi humilde opinión, esa es una verdadera peculiaridad en las especificaciones, pero no se puede eliminar sin romper los sitios web antiguos, que es algo que a los autores de especificaciones realmente no les gusta.
Así que sí, este getter con named
tendrá prioridad sobre cualquier otro getter heredado más adelante en la cadena de prototipos.
Si realmente no desea cambiar el name
de su elemento, lo que puede hacer es llamar explícitamente al captador Element.children
en su HTMLFormElement, o incluso más simple, probablemente pueda usar .querySelectorAll("*")
(suponiendo que no no tengo un elemento con tal nombre o id ;-)
const form = document.querySelector("form"); console.log("with .children:", form.children); // our <input> const getter = Object.getOwnPropertyDescriptor(Element.prototype, "children").get; console.log("with Element's getter:", getter.call(form)); // an HTMLCollection console.log("with querySelectorAll:", form.querySelectorAll("*")); // a NodeList
<form> <input name="foo"> <input name="children"> </form>