No se puede leer la propiedad 'addEventListener' de null


106

Tengo que usar JavaScript vainilla para un proyecto. Tengo algunas funciones, una de las cuales es un botón que abre un menú. Funciona en páginas donde existe la identificación de destino, pero causa un error en páginas donde la identificación no existe. En aquellas páginas donde la función no puede encontrar la identificación, recibo un error "No se puede leer la propiedad 'addEventListener' de nulo" y ninguna de mis otras funciones funciona.

A continuación se muestra el código del botón que abre el menú.

function swapper() {
toggleClass(document.getElementById('overlay'), 'open');
}

var el = document.getElementById('overlayBtn');
el.addEventListener('click', swapper, false);

var text = document.getElementById('overlayBtn');
text.onclick = function(){
this.innerHTML = (this.innerHTML === "Menu") ? "Close" : "Menu";
return false;
};

¿Cómo me enfrento a esto? Probablemente necesite envolver este código en otra función o usar una declaración if / else para que solo busque la identificación en páginas específicas, pero no estoy seguro exactamente.


1
¿Puedes mostrar el código html? parece que no se puede encontrar el elemento con id 'overlayBtn'
BlaShadow

2
En aquellas páginas donde la función no puede encontrar la identificación, recibo un error "No se puede leer la propiedad 'addEventListener' de nulo" y ninguna de mis otras funciones funciona. Creo que la respuesta estaba básicamente en la pregunta. No pudo encontrar el elemento, por lo que no puede agregarle un detector de eventos ...
Etai

1
Simplemente puede suceder si lo ha utilizado classen su html en lugar de idy solicita un getElementByIden sus scripts.
Deke

Respuestas:


197

Creo que el enfoque más fácil sería simplemente verificar que elno sea nulo antes de agregar un detector de eventos:

var el = document.getElementById('overlayBtn');
if(el){
  el.addEventListener('click', swapper, false);
}

increíble. eso hizo el truco. También moví la función onclick a esa declaración if. Publiqué el código final a continuación.
morocklo

3
¡Será nullantes de que se monte el componente de reacción!

Gracias hombre: D Exactamente lo que estaba buscando ... Tengo varios oyentes en mi aplicación, y los oyentes están distribuidos en diferentes vistas. Si el elemento está presente en la página, estaba estropeando mi JS
VegaStudios

¡Muy útil, gracias!
sc_props

113

Parece que document.getElementById('overlayBtn');está regresando nullporque se ejecuta antes de que el DOM se cargue por completo.

Si pones esta línea de código debajo

window.onload=function(){
  -- put your code here
}

entonces se ejecutará sin problemas.

Ejemplo:

window.onload=function(){
    var mb = document.getElementById("b");
    mb.addEventListener("click", handler);
    mb.addEventListener("click", handler2);
}


function handler() {
    $("p").html("<br>" + $("p").text() + "<br>You clicked me-1!<br>");
}

function handler2() {
    $("p").html("<br>" + $("p").text() + "<br>You clicked me-2!<br>");
}

23

Enfrenté una situación similar. Probablemente esto se deba a que el script se ejecuta antes de que se cargue la página. Al colocar el guión al final de la página, evité el problema.


1
Sí, creo que existen múltiples soluciones a este problema según el escenario.
rpeg

16

Recibí el mismo error, pero realizar una verificación nula no pareció ayudar.

La solución que encontré fue envolver mi función dentro de un detector de eventos para que todo el documento verifique cuando el DOM terminó de cargarse.

document.addEventListener('DOMContentLoaded', function () {
    el.addEventListener('click', swapper, false);
});

Creo que esto se debe a que estoy usando un marco (Angular) que está cambiando mis clases de HTML y mis ID de forma dinámica.


1
Me encuentro con el mismo problema cuando juego con Electron. Lo guardé usando el mismo método.
charles

9

Es solo porque su JS se carga antes que la parte HTML y, por lo tanto, no puede encontrar ese elemento. Simplemente coloque todo su código JS dentro de una función que se llamará cuando se cargue la ventana.

También puede poner su código Javascript debajo del html.


8

la secuencia de comandos se carga antes del cuerpo, mantenga la secuencia de comandos después del contenido


5

Ponga el guión al final de la etiqueta del cuerpo.

<html>
    <body>
        .........
        <script src="main.js"></script>
    </body>
</html>

3

Gracias a @Rob M. por su ayuda. Así es como se veía el bloque final de código:

function swapper() {
  toggleClass(document.getElementById('overlay'), 'open');
}

var el = document.getElementById('overlayBtn');
if (el){
  el.addEventListener('click', swapper, false);

  var text = document.getElementById('overlayBtn');
  text.onclick = function(){
    this.innerHTML = (this.innerHTML === "Menu") ? "Close" : "Menu";
    return false;
  };
}

2

Simplemente agregué 'async' a mi etiqueta de secuencia de comandos, que parece haber solucionado el problema. No estoy seguro de por qué, si alguien puede explicarme, pero funcionó para mí. Supongo que la página no está esperando a que se cargue el script, por lo que la página se carga al mismo tiempo que JavaScript.

Async / Await nos permite escribir código asincrónico de forma síncrona. es simplemente azúcar sintáctico usando generadores y declaraciones de rendimiento para "pausar" la ejecución, ¡dándonos la capacidad de asignarlo a una variable!

Aquí está el enlace de referencia: https://medium.com/siliconwat/how-javascript-async-await-works-3cab4b7d21da


2

Encontré el mismo problema y verifiqué nulo, pero no ayudó. Porque el script se estaba cargando antes de que se cargara la página. Entonces, simplemente colocando el script antes de la etiqueta del cuerpo final resolvió el problema.


0

Como han dicho otros, el problema es que el script se ejecuta antes de que se cargue la página (y en particular el elemento de destino).

Pero no me gusta la solución de reordenar el contenido.

La solución preferida es poner un controlador de eventos en el evento de carga de la página y establecer allí el Oyente. Eso asegurará que la página y el elemento de destino se carguen antes de que se ejecute la asignación. p.ej

    <script>
    function onLoadFunct(){
            // set Listener here, also using suggested test for null
    }
    ....
    </script>

    <body onload="onLoadFunct()" ....>
    .....

0

Tengo una colección de citas junto con nombres. Estoy usando el botón de actualización para actualizar la última cita asociada con un nombre específico, pero al hacer clic en el botón de actualización, no se actualiza. Incluyo el código a continuación para el archivo server.js y el archivo js externo (main.js).

main.js (js externos)

var update = document.getElementById('update');
if (update){
update.addEventListener('click', function () {

  fetch('quotes', {
  method: 'put',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    'name': 'Muskan',
    'quote': 'I find your lack of faith disturbing.'
  })
})var update = document.getElementById('update');
if (update){
update.addEventListener('click', function () {

  fetch('quotes', {
  method: 'put',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    'name': 'Muskan',
    'quote': 'I find your lack of faith disturbing.'
  })
})
.then(res =>{
    if(res.ok) return res.json()
})
.then(data =>{
    console.log(data);
    window.location.reload(true);
})
})
}

archivo server.js

app.put('/quotes', (req, res) => {
  db.collection('quotations').findOneAndUpdate({name: 'Vikas'},{
    $set:{
        name: req.body.name,
        quote: req.body.quote
    }
  },{
    sort: {_id: -1},
    upsert: true
  },(err, result) =>{
    if (err) return res.send(err);
    res.send(result);
  })

})

0

Gracias de todos, cargue los scripts en páginas específicas que usa, no para todas las páginas, a veces usando swiper.js u otra biblioteca puede causar este mensaje de error, la única forma de resolver este problema es cargar la biblioteca JS en páginas específicas ese ID existe y evita la carga de la misma biblioteca en todas las páginas.

Espero que esto te ayude.


0

Tuve el mismo problema, pero mi identificación estaba presente. Así que intenté agregar "window.onload = init;" Luego envolví mi código JS original con una función de inicio (llámalo como quieras). Esto funcionó, así que al menos en mi caso, estaba agregando un detector de eventos antes de que se cargara mi documento. Esto también podría ser lo que estás experimentando.


-1

Esto se debe a que el elemento no se había cargado en el momento en que se estaba ejecutando el paquete js.

Movería el <script src="sample.js" type="text/javascript"></script>al final del index.htmlarchivo. De esta manera, puede asegurarse de que el script se ejecute después de que todos los elementos html hayan sido analizados y procesados.


Incorrecto. Este es el pensamiento de la vieja escuela. La carga al final retrasa la carga, como dijiste, pero no garantiza que el DOM esté completamente dibujado . He tenido páginas más antiguas que usaron este truco que no se ejecutaron porque el dibujo DOM fue más lento que la carga. Esta respuesta asegura que el DOM se dibuje antes de la ejecución.
Machavity

-3

Agregue todos los detectores de eventos cuando se cargue una ventana. Funciona como un encanto sin importar dónde coloque las etiquetas de script.

window.addEventListener("load", startup);

function startup() {

  document.getElementById("el").addEventListener("click", myFunc);
  document.getElementById("el2").addEventListener("input", myFunc);

}

myFunc(){}

El dibujo de la página a veces puede llevar más tiempo que la carga del script, por lo que la posición no es tan importante en todos los casos. Agregar un oyente es la forma preferida, pero loadtambién está obsoleta por la misma razón. DOMContentLoaded es la forma preferida, ya que se activa solo después de que el DOM está completamente dibujado.
Machavity

Gracias lo intentaré. Obtuve mi respuesta de la red Mozilla. Pensé que era una fuente confiable.
Natalie Jimenez
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.