Force loadingTemplate to load on Iron

I would like to know how I could force loading template to have a minimum load time (ex: 3 seconds) before loading my default template / controller (App Controller).

Is that a way to do that using waitOn ? Thank you!

Router.configure({
controller: 'AppController',
loadingTemplate: 'loading'

});

AppController = RouteController.extend({
 layoutTemplate: 'appLayout'
});

Router.route('/', {
 name: 'home'
});

This could work :smiley:

waitOn: function() {
    var sub = Meteor.subscribe("something");
    var dep = new Tracker.Dependency();
    var isSubReady = false;
    var hasWaitTimePassed = false;
    var waitFor = 1000; // Wait for 1 sec

    Meteor.setTimeout(function() {
        hasWaitTimePassed = true;
        dep.changed();
    }, waitFor);

    Tracker.autorun(function() {
        isSubReady = sub.ready();
        dep.changed();
    });

    return {
        ready: function() {
            dep.depend();
            return hasWaitTimePassed && isSubReady;
        },
        stop: function() {
            sub.stop();
        }
    };
}

Hello Jorge - thank you very much for you answer.

I found this solution on stack overflow but in my case I have no subscriptions, so the bellow is not valid, please check my comments on the code bellow to see where I’m getting lost.

Router.configure({
  layoutTemplate: 'AppController',
  loadingTemplate: 'loading',
  waitOn: function() {
    //var sub = Meteor.subscribe("something"); 
    var dep = new Tracker.Dependency();
   var isSubReady = false;
   var hasWaitTimePassed = false;
   var waitFor = 1000; // Wait for 1 sec

   Meteor.setTimeout(function() {
      hasWaitTimePassed = true;
     dep.changed();
    }, waitFor);

    Tracker.autorun(function() {
      //isSubReady = sub.ready();
      dep.changed();
   });

   return {
       ready: function() {
           dep.depend();
           return hasWaitTimePassed;
           //&& isSubReady;
     },
    stop: function() {
        // What should I stop here?
        //sub.stop();
    }
};

}

});

Disclaimer: I don’t use Iron Router, so this is not guaranteed!

Router.configure({
  layoutTemplate: 'AppController',
  loadingTemplate: 'loading',
  waitOn: function() {
    var dep = new Tracker.Dependency();
    var hasWaitTimePassed = false;
    var waitFor = 1000; // Wait for 1 sec

    Meteor.setTimeout(function() {
      hasWaitTimePassed = true;
      dep.changed();
    }, waitFor);

    var comp = Tracker.autorun(function() {
      dep.changed();
    });

    return {
      ready: function() {
        dep.depend();
        return hasWaitTimePassed;
      },
      stop: function() {
        comp.stop();
      }
    };
  }
});

Easier without subs really.

waitOn: function() {
    var hasWaitTimePassed = new ReactiveVar(false);
    var waitFor = 3000; // Wait for 3 sec
    var stopped = false;

    Meteor.setTimeout(function() {
         if (!stopped) {
             hasWaitTimePassed.set(true);
         }
    }, waitFor);

    return {
        ready: function() {
            // hasWaitTimePassed is a reactive source, so this should do just fine
            return hasWaitTimePassed.get();
        },
        
        stop: function() {
             // Stopping should prevent the hasWaitTimePassed becoming true.
             stopped = true;
        }
    };
}

Hello Jorge

I did the changes you suggested and also put some console.log in my code to se result of it.

What is happening now is that the loadingTemplate does not stop loading and Router.route(’/’, {name: ‘home’}); is never being called.

From what I’ve seem, stop function() is never called.
I deployed my project on http://ns-timeout.meteor.com , so you can check my console.logs

**Thank you very very much for your time and patience **

Router.configure({
  layoutTemplate: 'AppController',
  loadingTemplate: 'loading',
  waitOn: function() {
      var hasWaitTimePassed = new ReactiveVar(false);
      var waitFor = 3000; // Wait for 3 sec
      var stopped = false;

       Meteor.setTimeout(function() {
           console.log('setTimeOut() hasWaitTimePassed :'+  hasWaitTimePassed.get());
           console.log('setTimeOut() stopped :'+  stopped);
           if (!stopped) {
               hasWaitTimePassed.set(true);
               console.log('setTimeOut() if(!stopped) : hasWaitTimePassed.set(true):'+  hasWaitTimePassed.get());
               console.log('setTimeOut() if(!stopped): '+  stopped);
           }
       }, waitFor);

      return {
         ready: function() {
             // hasWaitTimePassed is a reactive source, so this should do just fine
            console.log('return { ready function() hasWaitTimePassed :'+  hasWaitTimePassed.get());
            console.log('return { ready function() stopped :'+  stopped);
            return hasWaitTimePassed.get();
           },
          stop: function() {
               console.log('return { stop function() hasWaitTimePassed :'+  hasWaitTimePassed.get());
               console.log('return { stop function() stopped :'+  stopped);
            
              // Stopping should prevent the hasWaitTimePassed becoming true.
             stopped = true;
         }
       };
   }
});

Hmm, I think the problem might be that waitOn itself is reactive, and starts over when hasWaitTimePassed changes. This is one of the main drawbacks with iron:router as opposed to flow-router, everything is reactive, which can cause problems.

I’m not on a computer to test all these things, so I’m kind of shooting blind here, but try this:

Router.configure({
  layoutTemplate: 'AppController',
  loadingTemplate: 'loading',
  waitOn: function() {
      var loaded = false;
      return {
         ready: function() {
            if (!Session.get("loading") && !loaded) {
                Session.set("loading", true);

                setTimeout(function () {
                    Session.set("loading", false);
                    loaded = true;
                 }, 3000);
            }

            return !Session.get("loading");
           },
          stop: function() {
              // Dont think this is needed really.
         }
       };
   }
});

Hello Jorge

I tried your code but the issue is still the same… loadingTemplate is loaded by not rendered after 3 seconds :frowning:

Please check my code bellow and my comments to see if you can help me to find what I am doing wrong.
I also deployed this version so you can check my console.log()
http://ns1-timeout.meteor.com/

Thank you very much

Router.configure({
layoutTemplate: 'appLayout',
loadingTemplate: 'loading',
waitOn: function () {

    var isTimePassed = false;
    var clock = 3;

    var timeLeft = function() {
        if (clock > 0) {
            clock--;
            Session.set("time", clock);
            console.log(clock);

        } else {
            console.log("That's All");
            //return true
            isTimePassed = true;
            Meteor.clearInterval(interval);
            console.log('is Time passed: '+ isTimePassed);
            return isTimePassed; // seems it is being ignored

        }
    };

    var interval = Meteor.setInterval(timeLeft, 1000);

    return {
        ready: function () {
            console.log('return ready: ' + isTimePassed);
            return isTimePassed; // keeps the loading page and does not redirect to applayout if changed to false, loadingTemplate is not loaded and
        }

      }
    }
});

Ok, I finally got to test it, and this is what I came up with. It works on my setup at least.


<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button {{counter}} times.</p>
</template>

<template name="loading">
  <h1>Loading</h1>
</template>

<template name="AppController">
  {{> yield}}
</template>


// Making a fake subscription stub to imitate subscribing to something
var fakeSub = function (timeout) {
  var self = this;
  self._ready = false
  self._dep = new Tracker.Dependency();
  
  Meteor.setTimeout(function () {
    self._ready = true;
    self._dep.changed();
  }, timeout);
  
  return function () {
      self._dep.depend();
      return function () {
        return self._ready;
      }
    }
};

Router.configure({
  layoutTemplate: 'AppController',
  loadingTemplate: 'loading',
  waitOn: [fakeSub(3000)],
});

Router.route('/', {
  
   name: "hello" 
});
1 Like

Hello Jorge

Thank you so much for helping me.
Now is much clear why it would only work using Tracker.Dependency.

Best Regards :smile:

No worries :smile: Good luck with your project.