Não é possível ler a propriedade 'addEventListener' de nulo

106

Eu tenho que usar o JavaScript vanilla para um projeto. Tenho algumas funções, uma das quais é um botão que abre um menu. Funciona em páginas onde o id de destino existe, mas causa um erro nas páginas onde o id não existe. Nas páginas em que a função não consegue encontrar o id, recebo um erro "Não é possível ler a propriedade 'addEventListener' de nulo" e nenhuma das minhas outras funções funcionam.

Abaixo está o código do botão que abre o 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;
};

Como faço para lidar com isso? Provavelmente, preciso envolver todo esse código em outra função ou usar uma instrução if / else para que ele busque apenas o id em páginas específicas, mas não tenho certeza exatamente.

Morocklo
fonte
1
você pode mostrar o código html. parece que não é possível encontrar o elemento com id 'overlayBtn'
BlaShadow
2
Nas páginas em que a função não consegue encontrar o id, recebo um erro "Não é possível ler a propriedade 'addEventListener' de nulo" e nenhuma das minhas outras funções funcionam. Acho que a resposta estava basicamente na pergunta. Você não conseguiu encontrar o elemento, então não pode adicionar um ouvinte de evento a ele ...
Etai
1
Isso pode simplesmente acontecer se você tiver usado classem seu html em vez de ide solicitar um getElementByIdem seus scripts.
Deke

Respostas:

197

Acho que a abordagem mais fácil seria apenas verificar else não é nulo antes de adicionar um ouvinte de evento:

var el = document.getElementById('overlayBtn');
if(el){
  el.addEventListener('click', swapper, false);
}
Rob M.
fonte
impressionante. isso funcionou. Também movi a função onclick para essa instrução if. Eu postei o código final abaixo.
morocklo
3
será nullantes que o componente de reação seja montado!
Obrigado, cara: D Exatamente o que eu estava procurando ... Tenho vários ouvintes em meu aplicativo, e os ouvintes estão espalhados em visualizações diferentes. Se o elemento estiver presente na página, ele estava
bagunçando
Muito útil, obrigado!
sc_props
113

Parece que document.getElementById('overlayBtn');esta voltandonull porque é executado antes de o DOM carregar totalmente.

Se você colocar esta linha de código em

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

então ele será executado sem problemas.

Exemplo:

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
fonte
23

Eu enfrentei uma situação semelhante. Provavelmente, isso ocorre porque o script é executado antes do carregamento da página. Ao colocar o script na parte inferior da página, evitei o problema.

Sridhar
fonte
1
Sim, acho que existem várias soluções para esse problema, dependendo do cenário.
rpeg de
16

Eu estava recebendo o mesmo erro, mas a execução de uma verificação de nulos não parecia ajudar.

A solução que encontrei foi envolver minha função dentro de um ouvinte de evento para todo o documento para verificar quando o DOM terminou de carregar.

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

Acho que é porque estou usando um framework (Angular) que está mudando minhas classes HTML e IDs dinamicamente.

MattSidor
fonte
1
Eu tenho o mesmo problema quando jogo com Electron. Salvei usando o mesmo método.
Charles
9

É apenas bcz que seu JS é carregado antes da parte HTML e, portanto, não pode encontrar esse elemento. Basta colocar todo o seu código JS dentro de uma função que será chamada quando a janela for carregada.

Você também pode colocar seu código Javascript abaixo do html.

Ajit Kumar
fonte
8

o script está carregando antes do corpo, mantenha o script após o conteúdo

Sagar M
fonte
5

Coloque o script no final da tag body.

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

Obrigado a @Rob M. por sua ajuda. Esta é a aparência do bloco 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;
  };
}
Morocklo
fonte
2

Eu simplesmente adicionei 'async' à minha tag de script, o que parece ter corrigido o problema. Não sei por que, se alguém pode explicar, mas funcionou para mim. Meu palpite é que a página não está esperando o script carregar, então a página carrega ao mesmo tempo que o JavaScript.

Async / Await nos permite escrever código assíncrono de maneira síncrona. é apenas açúcar sintático usando geradores e declarações de rendimento para “pausar” a execução, nos dando a capacidade de atribuí-la a uma variável!

Aqui está o link de referência- https://medium.com/siliconwat/how-javascript-async-await-works-3cab4b7d21da

Andy Smith
fonte
2

Eu encontrei o mesmo problema e verifiquei se havia nulo, mas não ajudou. Porque o script estava carregando antes do carregamento da página. Portanto, apenas colocar o script antes da tag final do corpo resolveu o problema.

Mahmud
fonte
0

Como outros disseram, o problema é que o script é executado antes que a página (e em particular o elemento de destino) seja carregada.

Mas não gosto da solução de reordenar o conteúdo.

A solução preferida é colocar um manipulador de eventos no evento onload da página e definir o Listener lá. Isso garantirá que a página e o elemento de destino sejam carregados antes que a atribuição seja executada. por exemplo

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

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

Tenho uma coleção de citações junto com nomes. Estou usando o botão atualizar para atualizar a última citação associada a um nome específico, mas ao clicar no botão atualizar não está atualizando. Estou incluindo o código abaixo para o arquivo server.js e o arquivo js externo (main.js).

main.js (js externo)

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

arquivo 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
fonte
0

Obrigado de todos, carregue os scripts em páginas específicas que você usa, não para todas as páginas, às vezes usando swiper.js ou outra biblioteca pode causar esta mensagem de erro, a única maneira de resolver este problema é carregar a biblioteca JS em páginas específicas esse ID existe e evita o carregamento da mesma biblioteca em todas as páginas.

Espero que isso ajude você.

Baseer Ebadi
fonte
0

Eu tive o mesmo problema, mas minha identidade estava presente. Então tentei adicionar "window.onload = init;" Em seguida, envolvi meu código JS original com uma função init (chame do que quiser). Isso funcionou, então, pelo menos no meu caso, eu estava adicionando um ouvinte de evento antes de meu documento ser carregado. Isso pode ser o que você está experimentando também.

ultrageek
fonte
-1

Isso ocorre porque o elemento não foi carregado no momento em que o pacote js estava sendo executado.

Eu moveria o <script src="sample.js" type="text/javascript"></script>para o final do index.htmlarquivo. Dessa forma, você pode garantir que o script seja executado depois que todos os elementos html forem analisados ​​e renderizados.

Xcode
fonte
Incorreta. Este é o pensamento da velha escola. O carregamento no final atrasa o carregamento, como você declarou, mas não garante que o DOM seja totalmente desenhado . Eu tive páginas mais antigas que usaram esse hack que falharam ao executar porque o desenho do DOM era mais lento do que o carregamento. Essa resposta garante que o DOM seja desenhado antes da execução.
Machavity
-3

Adicione todos os ouvintes de evento quando uma janela for carregada. Funciona perfeitamente, não importa onde você coloque as tags de script.

window.addEventListener("load", startup);

function startup() {

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

}

myFunc(){}
Natalie Jimenez
fonte
O desenho da página às vezes pode demorar mais do que o carregamento do script, então a posição não é tão importante em todos os casos. Adicionar um ouvinte é a forma preferencial, mas loadtambém está obsoleta pelo mesmo motivo. DOMContentLoaded é a forma preferida, uma vez que dispara somente depois que o DOM é totalmente desenhado.
Machavity
Obrigado, vou tentar. Recebi minha resposta da rede Mozilla. Achei que fosse uma fonte confiável.
Natalie Jimenez