Impossible de lire la propriété 'addEventListener' de null

106

Je dois utiliser du JavaScript vanille pour un projet. J'ai quelques fonctions, dont l'une est un bouton qui ouvre un menu. Cela fonctionne sur les pages où l'ID cible existe, mais provoque une erreur sur les pages où l'ID n'existe pas. Sur les pages où la fonction ne trouve pas l'ID, je reçois une erreur "Impossible de lire la propriété 'addEventListener' de null" et aucune de mes autres fonctions ne fonctionne.

Voici le code du bouton qui ouvre le menu.

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

Comment gérer cela? J'ai probablement besoin de tout envelopper ce code dans une autre fonction ou d'utiliser une instruction if / else afin qu'il ne recherche que l'identifiant sur des pages spécifiques, mais pas exactement.

Morocklo
la source
1
pouvez-vous montrer le code html. il semble que ne peut pas trouver l'élément avec l'ID 'overlayBtn'
BlaShadow
2
Sur les pages où la fonction ne trouve pas l'ID, je reçois une erreur "Impossible de lire la propriété 'addEventListener' de null" et aucune de mes autres fonctions ne fonctionne. Je pense que la réponse était à peu près dans la question. Vous ne pouvez pas trouver l'élément, vous ne pouvez donc pas y ajouter un écouteur d'événement ...
Etai
1
Cela peut simplement arriver si vous avez utilisé classdans votre html au lieu de idet que vous appelez un getElementByIddans vos scripts.
Deke

Réponses:

198

Je pense que l'approche la plus simple serait de simplement vérifier que ce eln'est pas nul avant d'ajouter un écouteur d'événements:

var el = document.getElementById('overlayBtn');
if(el){
  el.addEventListener('click', swapper, false);
}
Rob M.
la source
impressionnant. cela a fait l'affaire. J'ai également déplacé la fonction onclick dans cette instruction if. J'ai posté le code final ci-dessous.
morocklo le
3
ce sera nullavant le montage du composant de réaction!
Merci mec: D Exactement ce que je cherchais ... J'ai plusieurs auditeurs dans mon application, et les auditeurs sont répartis dans des vues différentes. Si l'élément est présent sur la page, il était en
train de salir
Tellement utile, merci!
sc_props
113

Il semble que cela document.getElementById('overlayBtn');revient nullcar il s'exécute avant le chargement complet du DOM.

Si vous mettez cette ligne de code sous

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

alors il fonctionnera sans problème.

Exemple:

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>");
}
Dilip Agheda
la source
23

J'ai fait face à une situation similaire. C'est probablement parce que le script est exécuté avant le chargement de la page. En plaçant le script en bas de page, j'ai contourné le problème.

sridhar
la source
1
Ouais, je pense qu'il existe plusieurs solutions à ce problème selon le scénario.
rpeg
16

J'obtenais la même erreur, mais effectuer une vérification nulle ne semblait pas aider.

La solution que j'ai trouvée était d'envelopper ma fonction dans un écouteur d'événements pour tout le document afin de vérifier quand le DOM a fini de charger.

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

Je pense que c'est parce que j'utilise un framework (Angular) qui change dynamiquement mes classes HTML et mes ID.

MattSidor
la source
1
Je rencontre le même problème en jouant avec Electron. Je l'ai enregistré en utilisant la même méthode.
charles
9

C'est juste que votre JS est chargé avant la partie HTML et il ne peut donc pas trouver cet élément. Mettez simplement votre code JS dans une fonction qui sera appelée lorsque la fenêtre sera chargée.

Vous pouvez également mettre votre code Javascript sous le html.

Ajit Kumar
la source
8

le script se charge avant le corps, conserver le script après le contenu

Sagar M
la source
5

Mettez le script à la fin de la balise body.

<html>
    <body>
        .........
        <script src="main.js"></script>
    </body>
</html>
matak8s
la source
3

Merci à @Rob M. pour son aide. Voici à quoi ressemblait le dernier bloc de code:

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;
  };
}
Morocklo
la source
2

J'ai simplement ajouté «async» à ma balise de script, ce qui semble avoir résolu le problème. Je ne sais pas pourquoi, si quelqu'un peut expliquer, mais cela a fonctionné pour moi. Je suppose que la page n'attend pas le chargement du script, donc la page se charge en même temps que le JavaScript.

Async / Await nous permet d'écrire du code asynchrone de manière synchrone. c'est juste du sucre syntaxique utilisant des générateurs et des instructions yield pour «mettre en pause» l'exécution, ce qui nous donne la possibilité de l'assigner à une variable!

Voici le lien de référence - https://medium.com/siliconwat/how-javascript-async-await-works-3cab4b7d21da

Andy Smith
la source
2

J'ai rencontré le même problème et vérifié la valeur null, mais cela n'a pas aidé. Parce que le script se chargeait avant le chargement de la page. Donc, juste en plaçant le script avant la balise end body a résolu le problème.

Mahmud
la source
0

Comme d'autres l'ont dit, le problème est que le script est exécuté avant que la page (et en particulier l'élément cible) ne soit chargée.

Mais je n'aime pas la solution de réorganiser le contenu.

La solution préférée consiste à placer un gestionnaire d'événements sur l'événement de chargement de la page et à y définir l'écouteur. Cela garantira que la page et l'élément cible sont chargés avant l'exécution de l'affectation. par exemple

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

    <body onload="onLoadFunct()" ....>
    .....
pjm
la source
0

J'ai une collection de citations avec des noms. J'utilise le bouton de mise à jour pour mettre à jour le dernier devis associé à un nom spécifique, mais en cliquant sur le bouton de mise à jour, il ne se met pas à jour. J'inclus le code ci-dessous pour le fichier server.js et le fichier js externe (main.js).

main.js (js externes)

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);
})
})
}

fichier 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);
  })

})
Ambreen Fatima
la source
0

Merci à tous, chargez les scripts dans des pages spécifiques que vous utilisez, pas pour toutes les pages, parfois en utilisant swiper.js ou une autre bibliothèque, cela peut provoquer ce message d'erreur, le seul moyen de résoudre ce problème est de charger la bibliothèque JS sur des pages spécifiques cet identifiant existe et empêche le chargement de la même bibliothèque dans toutes les pages.

J'espère que cela vous aidera.

Baseer Ebadi
la source
0

J'ai eu le même problème, mais mon identité était présente. J'ai donc essayé d'ajouter "window.onload = init;" Ensuite, j'ai enveloppé mon code JS d'origine avec une fonction init (appelez-la comme vous voulez). Cela a fonctionné, donc au moins dans mon cas, j'ajoutais un écouteur d'événements avant le chargement de mon document. Cela pourrait aussi être ce que vous vivez.

ultrageek
la source
-1

Ceci est dû au fait que l'élément n'avait pas été chargé au moment où le bundle js était en cours d'exécution.

Je déplacerais <script src="sample.js" type="text/javascript"></script>tout en bas du index.htmlfichier. De cette façon, vous pouvez vous assurer que le script est exécuté après que tous les éléments html ont été analysés et rendus.

Xcode
la source
Incorrect. C'est une pensée à l'ancienne. Le chargement à la fin retarde le chargement, comme vous l'avez dit, mais cela ne garantit pas que le DOM est entièrement dessiné . J'ai eu des pages plus anciennes qui utilisaient ce hack ne fonctionnant pas parce que le dessin DOM était plus lent que la charge. Cette réponse garantit que le DOM est dessiné avant l'exécution.
Machavity
-3

Ajoutez tous les écouteurs d'événements lorsqu'une fenêtre se charge. Fonctionne comme un charme, peu importe où vous placez les balises de script.

window.addEventListener("load", startup);

function startup() {

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

}

myFunc(){}
Natalie Jimenez
la source
Le dessin de la page peut parfois prendre plus de temps que le chargement du script, donc la position n'est pas si importante dans tous les cas. L'ajout d'un écouteur est la méthode préférée, mais loadest également déconseillée pour la même raison. DOMContentLoaded est le moyen préféré, car il se déclenche uniquement après que le DOM est entièrement dessiné.
Machavity
Merci je vais essayer. J'ai eu ma réponse du réseau Mozilla. Je pensais que c'était une source de confiance.
Natalie Jimenez