2

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.

Hativ
  • 1,282
  • 1
  • 13
  • 23

2 Answers2

0
 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.

theblindprophet
  • 7,260
  • 5
  • 29
  • 49
  • This is a single page app, which gets already loaded after DOM is ready. The DOM manipulation with setView() before trying to add event listeners is working. If, then the manipulated DOM would't be ready. Is that possible? – Hativ Mar 21 '16 at 19:31
0

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.

Community
  • 1
  • 1
dev7
  • 5,818
  • 5
  • 27
  • 58
  • This is a single page app, which gets already loaded after DOM is ready. The DOM manipulation with setView() before trying to add event listeners is working. If, then the manipulated DOM would't be ready. Is that possible? – Hativ Mar 21 '16 at 19:31
  • @Kiltarc If you're loading it via Ajax then try setting a callback that is executed when the load is complete. And then (and only then) register this events. I'm adding another solution to my answer. – dev7 Mar 21 '16 at 19:34