javascript - ejemplo - ¿Por qué jQuery o un método DOM como getElementById no encuentran el elemento?
getelementbyid value (6)
¿Cuáles son las posibles razones para document.getElementById
, $("#id")
o cualquier otro selector de método / jQuery DOM que no encuentre los elementos?
Ejemplos de problemas incluyen:
- jQuery silenciosamente al enlazar un controlador de eventos
- Métodos jQuery "getter" (
.val()
,.html()
,.text()
) devolviendoundefined
Un método DOM estándar que devuelve un
null
produce cualquiera de varios errores:No se detectó TypeError: no se puede establecer la propiedad ''...'' de null. No se detectó TypeError: no se puede leer la propiedad ''...'' de null
Las formas más comunes son:
No se detectó TypeError: no se puede establecer la propiedad ''onclick'' de null
No se detectó TypeError: no se puede leer la propiedad ''addEventListener'' de null
Error de tipo no detectado: no se puede leer la propiedad ''estilo'' de nulo
Como señaló @FelixKling, el escenario más probable es que los nodos que está buscando no existen (todavía).
Sin embargo, las prácticas de desarrollo modernas a menudo pueden manipular elementos de documentos fuera del árbol de documentos con DocumentFragments o simplemente separar / volver a unir elementos actuales directamente. Dichas técnicas se pueden usar como parte de las plantillas de JavaScript o para evitar operaciones excesivas de repintado / reflujo mientras los elementos en cuestión están siendo muy alterados.
De manera similar, la nueva funcionalidad "Shadow DOM" que se está implementando en los navegadores modernos permite que los elementos formen parte del documento, pero no pueden ser consultados por document.getElementById y todos sus métodos relacionados (querySelector, etc.). Esto se hace para encapsular la funcionalidad y ocultarla específicamente.
Sin embargo, una vez más, es muy probable que el elemento que está buscando simplemente no esté (todavía) en el documento, y debe hacer lo que sugiere Felix. Sin embargo, también debe tener en cuenta que esa no es cada vez más la única razón por la que un elemento puede ser inoperable (ya sea temporal o permanentemente).
El elemento que estaba tratando de encontrar no estaba en el DOM cuando se ejecutó su script.
La posición de su script dependiente de DOM puede tener un efecto profundo en su comportamiento. Los navegadores analizan los documentos HTML de arriba a abajo. Los elementos se agregan al DOM y los scripts (generalmente) se ejecutan a medida que se encuentran. Esto significa que el orden importa. Por lo general, los scripts no pueden encontrar elementos que aparecen más adelante en el marcado porque esos elementos aún no se han agregado al DOM.
Considere el siguiente marcado; el script # 1 no encuentra el <div>
mientras el script # 2 tiene éxito:
<script>
console.log("script #1: %o", document.getElementById("test")); // null
</script>
<div id="test">test div</div>
<script>
console.log("script #2: %o", document.getElementById("test")); // <div id="test" ...
</script>
¿Entonces, qué debería hacer? Tienes algunas opciones:
Opción 1: Mueve tu guión
Mueva su script más abajo en la página, justo antes de la etiqueta de cierre del cuerpo. Organizado de esta manera, el resto del documento se analiza antes de ejecutar el script:
<body>
<button id="test">click me</button>
<script>
document.getElementById("test").addEventListener("click", function() {
console.log("clicked: %o", this);
});
</script>
</body><!-- closing body tag -->
Nota: la colocación de scripts en la parte inferior generalmente se considera una mejor práctica .
Opción 2: jQuery está ready()
Aplace su secuencia de comandos hasta que el DOM se haya analizado completamente, utilizando ready()
:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#test").click(function() {
console.log("clicked: %o", this);
});
});
</script>
<button id="test">click me</button>
Nota: Simplemente puede enlazar a DOMContentLoaded
o window. onload
onload
pero cada uno tiene sus advertencias. jQuery ready()
ofrece una solución híbrida.
Opción 3: Delegación de eventos
Los eventos delegados tienen la ventaja de que pueden procesar eventos de elementos descendientes que se agregan al documento en un momento posterior.
Cuando un elemento provoca un evento (siempre que sea un evento bubbling y nada detenga su propagación), cada padre en la ascendencia de ese elemento también recibe el evento. Eso nos permite adjuntar un controlador a un elemento existente y eventos de muestra a medida que surgen de sus descendientes ... incluso aquellos que se agregan después de que se adjunta el controlador. Todo lo que tenemos que hacer es verificar el evento para ver si fue generado por el elemento deseado y, de ser así, ejecutar nuestro código.
jQuery''s on()
realiza esa lógica para nosotros. Simplemente proporcionamos un nombre de evento, un selector para el descendiente deseado y un controlador de eventos:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).on("click", "#test", function(e) {
console.log("clicked: %o", this);
});
</script>
<button id="test">click me</button>
Nota: Normalmente, este patrón se reserva para elementos que no existían en el tiempo de carga o para evitar adjuntar una gran cantidad de manejadores. También vale la pena señalar que, si bien he adjuntado un controlador al document
(con fines demostrativos), debe seleccionar el antepasado confiable más cercano.
Opción 4: El atributo de defer
Utilice el atributo de defer
de <script>
.
[
defer
, un atributo booleano,] se configura para indicar a un navegador que el script debe ejecutarse después de que el documento haya sido analizado.
<script src="https://gh-canon.github.io/misc-demos/log-test-click.js" defer></script>
<button id="test">click me</button>
Para referencia, aquí está el código de ese script externo :
document.getElementById("test").addEventListener("click", function(e){
console.log("clicked: %o", this);
});
Nota: el atributo de defer
ciertamente parece una bala mágica, pero es importante estar al tanto de las advertencias ...
1. el defer
solo se puede utilizar para scripts externos, es decir, aquellos que tienen un atributo src
.
2. Esté al tanto de la compatibilidad del navegador , es decir: implementación con errores en IE <10
Intente poner document.getElementById
en setTimeout()
P.ej
setTimeout(function(){
console.log(document.getElementById(''whatever''));
}, 100);
Si esto funciona, entonces es solo un problema de tiempo.
Si el elemento al que intenta acceder está dentro de un iframe
e intenta acceder a él fuera del contexto del iframe
esto también hará que falle.
Si desea obtener un elemento en un iframe, puede encontrar información here .
Corto y simple: porque los elementos que busca no existen en el documento (todavía).
Para el resto de esta respuesta getElementById
como ejemplo, pero lo mismo se aplica a getElementsByTagName
, querySelector
y cualquier otro método DOM que seleccione elementos.
Posibles razones
Hay dos razones por las que un elemento podría no existir:
Un elemento con la ID pasada realmente no existe en el documento. Debería verificar que el ID que pasa a
getElementById
realmente coincida con un ID de un elemento existente en el HTML (generado) y que no haya escrito incorrectamente el ID (los ID distinguen entre mayúsculas y minúsculas ).Por cierto, en la mayoría de los navegadores contemporáneos , que implementan los
querySelector()
yquerySelectorAll()
, la notación de estilo CSS se usa para recuperar un elemento por suid
, por ejemplo:document.querySelector(''#elementID'')
, en oposición a el método por el cual un elemento es recuperado por suid
endocument.getElementById(''elementID'')
; en el primero, el carácter#
es esencial, en el segundo conduciría a que el elemento no se recupere.El elemento no existe en el momento en que llama a
getElementById
.
El último caso es bastante común. Los navegadores analizan y procesan el HTML de arriba a abajo. Eso significa que cualquier llamada a un elemento DOM que ocurra antes de que ese elemento DOM aparezca en el HTML, fallará.
Considere el siguiente ejemplo:
<script>
var element = document.getElementById(''my_element'');
</script>
<div id="my_element"></div>
El div
aparece después de la script
. En el momento en que se ejecuta el script, el elemento aún no existe y getElementById
devolverá el null
.
jQuery
Lo mismo se aplica a todos los selectores con jQuery. jQuery no encontrará elementos si escribió incorrectamente su selector o si intenta seleccionarlos antes de que realmente existan .
Un giro adicional es cuando no se encuentra jQuery porque ha cargado el script sin protocolo y se está ejecutando desde el sistema de archivos:
<script src="//somecdn.somewhere.com/jquery.min.js"></script>
esta sintaxis se utiliza para permitir que el script se cargue a través de HTTPS en una página con el protocolo https: // y para cargar la versión HTTP en una página con el protocolo http: //
Tiene el desafortunado efecto secundario de intentar y no cargar el file://somecdn.somewhere.com...
Soluciones
Antes de realizar una llamada a getElementById
(o cualquier otro método DOM), asegúrese de que existan los elementos a los que desea acceder, es decir, el DOM está cargado.
Esto se puede garantizar simplemente colocando su JavaScript después del elemento DOM correspondiente
<div id="my_element"></div>
<script>
var element = document.getElementById(''my_element'');
</script>
en cuyo caso también puede colocar el código justo antes de la etiqueta de cuerpo de cierre ( </body>
) (todos los elementos DOM estarán disponibles en el momento en que se ejecute el script).
Otras soluciones incluyen escuchar los eventos de load
[MDN] o DOMContentLoaded
[MDN] . En estos casos, no importa en qué lugar del documento coloque el código JavaScript, solo debe recordar colocar todo el código de procesamiento DOM en los controladores de eventos.
Ejemplo:
window.onload = function() {
// process DOM elements here
};
// or
// does not work IE 8 and below
document.addEventListener(''DOMContentLoaded'', function() {
// process DOM elements here
});
Consulte los artículos en quirksmode.org para obtener más información sobre el manejo de eventos y las diferencias de navegador.
jQuery
Primero asegúrese de que jQuery está cargado correctamente. Utilice las herramientas de desarrollo del navegador para averiguar si se encontró el archivo jQuery y corrija la URL si no fue así (por ejemplo, agregue el esquema http:
o https:
al principio, ajuste la ruta, etc.)
Escuchar los eventos load
/ DOMContentLoaded
es exactamente lo que está haciendo jQuery con ready() . Todo el código jQuery que afecta al elemento DOM debe estar dentro de ese controlador de eventos.
De hecho, el tutorial de jQuery establece explícitamente:
Como casi todo lo que hacemos cuando usamos jQuery lee o manipula el modelo de objeto de documento (DOM), debemos asegurarnos de que comencemos a agregar eventos, etc., tan pronto como el DOM esté listo.
Para ello, registramos un evento listo para el documento.
$(document).ready(function() { // do stuff when DOM is ready });
Alternativamente, también puede utilizar la sintaxis abreviada:
$(function() {
// do stuff when DOM is ready
});
Ambos son equivalentes.
Razones por las que los selectores basados en id no funcionan
- El elemento / DOM con id especificado no existe todavía.
- El elemento existe, pero no está registrado en DOM [en caso de que los nodos HTML se agreguen dinámicamente de las respuestas de Ajax].
- Más de un elemento con el mismo id está presente, lo que está causando un conflicto.
Soluciones
Intente acceder al elemento después de su declaración o, alternativamente, utilice cosas como
$(document).ready();
Para los elementos que provienen de las respuestas de Ajax, use el método
.bind()
de jQuery. Las versiones anteriores de jQuery tenían.live()
para el mismo.Use herramientas [por ejemplo, el complemento webdeveloper para navegadores] para encontrar identificaciones duplicadas y eliminarlas.