简体   繁体   中英

Javascript: addEventListener only working in setTimeout

I'm trying to set event listeners but it's only working if I set them within setTimeout.

Doesn't work:

WebApp.setController('jobs', function() {
  WebApp.setView('header', 'header');
  WebApp.setView('nav', 'nav');
  WebApp.setView('jobs', 'main');

  var jobs = document.querySelectorAll('.jobs-category');
  for(let i = 0; i < jobs.length; i++)
  {
    console.log('events added');
    jobs[i].addEventListener("dragover", function( event ) {
      console.log('drag over');
      event.preventDefault();
    });
    jobs[i].addEventListener('drop', function(event) {
      event.preventDefault();
      console.log('dropped');
    }, false);
  }

});

Does work:

WebApp.setController('jobs', function() {
  WebApp.setView('header', 'header');
  WebApp.setView('nav', 'nav');
  WebApp.setView('jobs', 'main');

  window.setTimeout(function() {
    var jobs = document.querySelectorAll('.jobs-category');
    for(let i = 0; i < jobs.length; i++)
    {
      console.log('events added');
      jobs[i].addEventListener("dragover", function( event ) {
        console.log('drag over');
        event.preventDefault();
      });
      jobs[i].addEventListener('drop', function(event) {
        event.preventDefault();
        console.log('dropped');
      }, false);
    }
  }, 1);

});

(only setTimout is different/additionally)

setController() saves the function and executes it if the route get requested.

setView() binds HTML5-templates to DOM:

  var Template = document.querySelector('#' + Name);
  var Clone = document.importNode(Template.content, true);
  var CloneElement = document.createElement('div');
  CloneElement.appendChild(Clone);
  CloneElement = this.replacePlaceholders(CloneElement);
  document.querySelector(Element).innerHTML = CloneElement.innerHTML;

Why does this only work in setTimeout? I thought javascript is synchronous.

Addition: This is a single page app, which gets already loaded after DOM is ready.

 document.addEventListener("DOMContentLoaded",      function(event) { 
   //do work
});

Most likely you are loading your JS file before your html content. You can't run your Javascript functions until the DOM is ready.

Where is your Javascript within the page?

My guess is that the HTML is not ready yet when you try to register the event, this is why it only works with setTimeout .

Try either including your javascript at the bottom of the page (after the HTML) or listening to the page loaded event. See this question for info how to do that - $(document).ready equivalent without jQuery .

Per your assumption of synchronous javascript - yes it is (mostly) but also the way that the browser renders the page is (unless using async loading of scripts). Which means that HTML that is after a javascript will not be available yet.

UPDATE - per your comment of using a single page app, you must listen to the load complete/done/successful event. Another way you could bypass it will be listening to the events on the parent element (which is always there).

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM