11

I want to create a preloading script that performs a number of async functions to download external content. I'm pretty close here, but I haven't quite figured out how to to defer calling this.next() in my onBeforeAction function. In the code below you can see I use a loop and setTimeout but I lose the context of my router somehow and this.next() is undefined. I believe this is because my preloadProject function gets to the end and the Router warns me that I forgot to call this.next(); prior to my waitToRender function completing.

if (Meteor.isClient) {
    IR_BeforeHooks = {
        preloadProject: function() {
            var itemsProcessed = 0;
            _.each(items.items, function(e) {
                    HTTP.get(e.S3URL, {
                            headers: {
                                'Accept': '*/*'
                            },
                            responseType: 'arraybuffer' //requires aldeed:http
                        }, function(error, result) {
                            if (error) {
                                Session.set('error', {
                                    'title': 'Could not download',
                                    'message': error
                                });
                            }
                            if (result) {
                                itemsProcessed = itemsProcessed + 1;
                            }
                        }) //http get
                }) //each
            function waitToRender(router) {
                console.log('waiting...')
                var progress = (itemsProcessed / items.items.length) * 100;
                if (progress < 100) {
                    $('.progress-bar').css('width', Math.floor(progress) + '%');
                    setTimeout((function() {
                        waitToRender(router);
                    }), 50);
                    //console.log('timeout for a few ms here')
                }
                else {
                    console.log('all done, render');
                    router.next(); // I get this is not a function error here
                }
            }
            waitToRender(this);
        }
    }
}

and my router

Router.before(
    IR_BeforeHooks.preloadProject, 
    {
        only:['editor', 'viewer', 'embedder']
    }
);

Because of complicated requirements in my project I need to perform these tasks before rendering. How can I get Iron Router to wait on my http calls without blocking the browser?

danSiebes
  • 374
  • 1
  • 12

2 Answers2

1

I've found a solution. The problem, as I suspected, was that Iron Router was nulling itself when my primary hook function finished its sync work. So to fix this I setup my own copy of this.next when I start my work, and call my copy of the function when my async work is completed.

IR_BeforeHooks = {
  preloadProject: function() {
    var myNext = this.next;
    ...//http calls and etc
    function waitToRender(router) {
      console.log('waiting...')
      var progress = (itemsProcessed / items.items.length) * 100;
      if (progress < 100) {
        ...//use set timeout to recall waitToRender
      }
      else{
        myNext();
      }
    }
  }
}
danSiebes
  • 374
  • 1
  • 12
  • I am trying to resolve a related issue. Kindly help me out with this [link] (https://stackoverflow.com/questions/46072958/where-do-i-place-my-meteor-callpromise-code-so-it-works-with-my-waiton-hook) Thanks in advance. – SirBT Sep 08 '17 at 12:18
0

Put router.next() outside else block, even if you're not rendering anything you need to call next.

 if (progress < 100) {
                        $('.progress-bar').css('width', Math.floor(progress) + '%');
                        setTimeout((function() {
                            waitToRender(router);
                        }), 50);
                        //console.log('timeout for a few ms here')
                    }
                    else {
                        console.log('all done, render');
                    }
router.next(); 
sam100rav
  • 3,733
  • 4
  • 27
  • 43
  • I appreciate the reply, the issue is that I don't want to render until progress is at 100. If I put router.next() where you recommend then I will end up rendering at the end of the first iteration of waitToRender and calling router.next over and over again until my http calls are done. – danSiebes Nov 02 '15 at 16:47