¿Cuáles son las posibles razones para document.getElementById
, $("#id")
o cualquier otro método DOM / jQuery selector para no encontrar los elementos?
Los problemas de ejemplo incluyen:
- jQuery silenciosamente no puede vincular un controlador de eventos
- jQuery métodos "getter" (
.val()
,.html()
,.text()
) devolverundefined
- Un método DOM estándar que devuelve el
null
resultado de cualquiera de varios errores:
TypeError no capturado: no se puede establecer la propiedad '...' de nulo TypeError no capturado: no se puede leer la propiedad '...' de nulo
Las formas más comunes son:
TypeError no capturado: no se puede establecer la propiedad 'onclick' de nulo
TypeError no capturado: no se puede leer la propiedad 'addEventListener' de null
TypeError no capturado: no se puede leer la propiedad 'estilo' de nulo
javascript
jquery
dom
Felix Kling
fuente
fuente
Respuestas:
El elemento que intentaba encontrar no estaba en el DOM cuando se ejecutó su script.
La posición de su script dependiente de DOM puede tener un profundo efecto sobre su comportamiento. Los navegadores analizan los documentos HTML de arriba a abajo. Los elementos se agregan al DOM y los scripts se ejecutan (generalmente) 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 puede encontrar el
<div>
script while # 2 tiene éxito:¿Entonces, qué debería hacer? Tienes algunas opciones:
Opción 1: mueve tu script
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:
Nota: colocar guiones en la parte inferior generalmente se considera una práctica recomendada .
Opción 2: jQuery's
ready()
Aplaza tu secuencia de comandos hasta que el DOM se haya analizado por completo, usando :
$(handler)
Nota: Usted puede simplemente enlazar con
DOMContentLoaded
o pero cada uno tiene sus advertencias. jQuery's ofrece una solución híbrida.window.onload
ready()
Opción 3: Delegación de eventos
Cuando un elemento genera un evento (siempre que sea un evento burbujeante 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 los que se agregan después de adjuntar 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 por nosotros. Simplemente proporcionamos un nombre de evento, un selector para el descendiente deseado y un controlador de eventos:Nota: Normalmente, este patrón está reservado para elementos que no existían en el momento de la carga o para evitar asociar una gran cantidad de controladores. También vale la pena señalar que si bien he adjuntado un controlador a
document
(con fines demostrativos), debe seleccionar el antepasado confiable más cercano.Opción 4: el
defer
atributoUsa el
defer
atributo de<script>
.Como referencia, aquí está el código de ese script externo :
Nota: El
defer
atributo ciertamente parece una bala mágica, pero es importante tener en cuenta las advertencias ...1.
defer
solo se puede usar para scripts externos, es decir, aquellos que tienen unsrc
atributo.2. Tenga en cuenta la compatibilidad del navegador , es decir: implementación defectuosa en IE <10
fuente
<head>
y los usodefer
(no tengo que admitir navegadores incompatibles antiguos)defer
yasync
tienen un soporte bastante amplio, incluso llegando a algunas versiones de navegador mucho más antiguas. Tienen la ventaja adicional de señalar de manera clara y explícita el comportamiento deseado. Solo recuerde que estos atributos solo funcionan para scripts que especifican unsrc
atributo, es decir: scripts externos. Sopesa los beneficios. Tal vez use ambos? Tu llamada.Breve y simple: porque los elementos que está buscando no existen en el documento (todavía).
Para el resto de esta respuesta voy a utilizar
getElementById
como ejemplo, pero lo mismo se aplica agetElementsByTagName
,querySelector
y cualquier otro método DOM que los elementos seleccione.Posibles razones
Hay dos razones por las cuales un elemento podría no existir:
Un elemento con la ID pasada realmente no existe en el documento. Debe verificar que la ID que pasa
getElementById
realmente coincida con la ID de un elemento existente en el HTML (generado) y que no haya escrito mal la ID (¡las ID distinguen entre mayúsculas y minúsculas !).Por cierto, en la mayoría de los navegadores contemporáneos , que implementan
querySelector()
yquerySelectorAll()
métodos, la notación de estilo CSS se utiliza para recuperar un elemento por suid
, por ejemplo:, adocument.querySelector('#elementID')
diferencia del método por el cual un elemento se recupera porid
debajodocument.getElementById('elementID')
; en el primero el#
personaje es esencial, en el segundo llevaría a que el elemento no se recupere.El elemento no existe en el momento que llamas
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:
El
div
aparece después de lascript
. En el momento en que se ejecuta la secuencia de comandos, el elemento no existe todavía ygetElementById
volveránull
.jQuery
Lo mismo se aplica a todos los selectores con jQuery. jQuery no encontrará elementos si ha escrito mal su selector o está intentando 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:
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
file://somecdn.somewhere.com...
Soluciones
Antes de hacer una llamada a
getElementById
(o cualquier método DOM para el caso), asegúrese de que los elementos a los que desea acceder existan, es decir, que el DOM esté cargado.Esto se puede garantizar simplemente colocando su JavaScript después del elemento DOM correspondiente
en cuyo caso también puede poner el código justo antes de la etiqueta del 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
load
[MDN] oDOMContentLoaded
[MDN] . En estos casos, no importa en qué parte del documento coloque el código JavaScript, solo debe recordar colocar todo el código de procesamiento DOM en los controladores de eventos.Ejemplo:
Consulte los artículos en quirksmode.org para obtener más información sobre el manejo de eventos y las diferencias del 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:
ohttps:
al principio, ajuste la ruta, etc.)Escuchar los eventos
load
/DOMContentLoaded
es exactamente lo que está haciendo jQuery con.ready()
[docs] . Todo el código jQuery que afecta al elemento DOM debe estar dentro de ese controlador de eventos.De hecho, el tutorial jQuery declara explícitamente:
Alternativamente, también puede usar la sintaxis abreviada:
Ambos son equivalentes.
fuente
ready
evento para reflejar la sintaxis preferida "más reciente", o es mejor dejarlo como está para que funcione en versiones anteriores?$(window).load()
(y posiblemente alternativas sintácticas al$(document).ready()
,$(function(){})
Se parece estar relacionado, pero? Se siente ligeramente tangencial al punto que está haciendo..load
. Con respecto a las alternativas de sintaxis, podrían buscarse en la documentación, pero dado que las respuestas deben ser independientes, en realidad valdría la pena agregarlas. Por otra parte, estoy bastante seguro de que este bit específico sobre jQuery ya fue respondido y probablemente esté cubierto en otras respuestas y puede ser suficiente vincularlo..load
está en desuso: api.jquery.com/load-event . No sé si es solo para imágenes owindow
también.Razones por las cuales los selectores basados en id no funcionan
Soluciones
Intente acceder al elemento después de su declaración o, alternativamente, use cosas como
$(document).ready();
Para los elementos que provienen de las respuestas de Ajax, use el
.bind()
método de jQuery. Las versiones anteriores de jQuery tenían.live()
lo mismo.Use herramientas [por ejemplo, plugin de desarrollador web para navegadores] para buscar identificadores duplicados y eliminarlos.
fuente
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 del documento fuera del árbol de documentos, ya sea con DocumentFragments o simplemente separando / volviendo a colocar los elementos actuales directamente. Dichas técnicas se pueden usar como parte de la plantilla de JavaScript o para evitar operaciones excesivas de repintado / reflujo mientras los elementos en cuestión se alteran mucho.
Del mismo modo, la nueva funcionalidad "Shadow DOM" que se implementa en los navegadores modernos permite que los elementos formen parte del documento, pero que no se puedan consultar por document.getElementById y todos sus métodos hermanos (querySelector, etc.). Esto se hace para encapsular la funcionalidad y ocultarla específicamente.
Sin embargo, de nuevo, 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 inaccesible (ya sea temporal o permanentemente).
fuente
Si el elemento al que intenta acceder está dentro de
iframe
e e intenta acceder fuera del contexto deiframe
esto, esto también hará que falle.Si desea obtener un elemento en un iframe, puede averiguar cómo hacerlo aquí .
fuente
Si el problema no es el orden de ejecución del script, otra posible causa del problema es que el elemento no se está seleccionando correctamente:
getElementById
requiere que la cadena pasada sea el ID literal , y nada más. Si antepone la cadena pasada con a#
, y la ID no comienza con a#
, no se seleccionará nada:Del mismo modo, para
getElementsByClassName
, no prefijas la cadena pasada con un.
:Con querySelector, querySelectorAll y jQuery, para hacer coincidir un elemento con un nombre de clase particular, coloque un elemento
.
directamente antes de la clase. Del mismo modo, para hacer coincidir un elemento con un ID en particular, coloque un#
directamente antes del ID:Las reglas aquí son, en la mayoría de los casos, idénticas a las de los selectores CSS, y se pueden ver en detalle aquí .
Para hacer coincidir un elemento que tiene dos o más atributos (como dos nombres de clase, o un nombre de clase y un
data-
atributo), coloque los selectores para cada atributo uno al lado del otro en la cadena de selección, sin un espacio que los separe (porque un espacio indica El selector descendiente ). Por ejemplo, para seleccionar:usa la cadena de consulta
.foo.bar
. Para seleccionarusa la cadena de consulta
.foo[data-bar="someData"]
. Para seleccionar lo<span>
siguiente:uso
div.parent > span[data-username="bob"]
.Las mayúsculas y la ortografía son importantes para todo lo anterior. Si la capitalización es diferente, o la ortografía es diferente, el elemento no se seleccionará:
También debe asegurarse de que los métodos tengan las mayúsculas y la ortografía adecuadas. Use uno de:
Cualquier otra ortografía o capitalización no funcionará. Por ejemplo,
document.getElementByClassName
arrojará un error.Asegúrese de pasar una cadena a estos métodos de selección. Si pasa algo que no es una cadena a
querySelector
,getElementById
, etc, es casi seguro que no va a funcionar.fuente
Cuando probé tu código, funcionó.
La única razón por la que su evento no funciona es que su DOM no estaba listo y su botón con la identificación "event-btn" aún no estaba listo. Y su javascript se ejecutó e intentó vincular el evento con ese elemento.
Antes de usar el elemento DOM para el enlace, ese elemento debe estar listo. Hay muchas opciones para hacer eso.
Opción 1: puede mover su código de enlace de evento dentro del evento de documento listo. Me gusta:
Opción 2: puede usar el evento de tiempo de espera, de modo que el enlace se retrase durante unos segundos. me gusta:
Opción 3: mueva su javascript incluido al final de su página.
Espero que esto te ayude.
fuente
El problema es que el elemento dom 'speclist' no se crea en el momento en que se ejecuta el código JavaScript. Así que puse el código javascript dentro de una función y llamé a esa función en el evento de carga del cuerpo.
fuente
Mi solución fue la de no utilizar el id de un elemento de anclaje:
<a id='star_wars'>Place to jump to</a>
. Aparentemente, Blazor y otros marcos de spa tienen problemas para saltar a los anclajes en la misma página. Para evitar eso tuve que usardocument.getElementById('star_wars')
. Sin embargo esto no funcionó hasta que ponga el id en un elemento de párrafo en su lugar:<p id='star_wars'>Some paragraph<p>
.Ejemplo usando bootstrap:
fuente