18

In routeProvider we can hold the routing if we give a resolve object which contains promises; it would wait until all the promises are resolved. However, I couldn't find a way do it in initialization of the application.

There is angular.module("app", []).run(function (){ //init app }) but for a $resource or $http which is async, the app can finish initialization before the dependencies (promises) are resolved that would create a race condition. We don't want that.

So the question is, is there a way which would hold the initialization of a service until all the given promises are resolved?

Umur Kontacı
  • 35,403
  • 8
  • 73
  • 96
  • 1
    Don't you want [Manual Initialization](http://docs.angularjs.org/guide/bootstrap)? – Jared Farrish Dec 31 '12 at 08:02
  • 1
    Setting a callback to manual init of a promise resolve would work, however it is not elegant, angular has a great DI, why can't we benefit from that? Like *if the dependency is a promise, resolve it before going further* – Umur Kontacı Dec 31 '12 at 08:20
  • Since you didn't include yourj apps actual code, I can't tell but I think this questions is covering the same issue: http://stackoverflow.com/questions/12265565/angularjs-promise-is-resolved-before-data-is-loaded?rq=1 – Jared Farrish Dec 31 '12 at 09:41
  • No, I want to hold the init of a service until the promises are resolved, this is a generic question, does not need a source. – Umur Kontacı Dec 31 '12 at 09:53
  • I just think I need to see what you have in mind in the sense of promises "broken" (if you will). If you have a `$http` promise tied to your `$resource` promise, before `init`, wouldn't `then()/when()` be used to reach the `resolve(init)`? Or all else fails, run a `$timeout` in `run(init)` instead of anonymously, so you can check state or pass it back to the other promise to call. I don't know, my heads stuffy so I could just be under the weather. I'm one of those people who has to see the issue, and since my Angular skills are underdeveloped, I'll just wait and see what others say. – Jared Farrish Dec 31 '12 at 10:46
  • I saw your website too. So true. one of these days it'll *rock*. – Jared Farrish Dec 31 '12 at 10:49
  • Can't you wrap asyncronuous services like $http, $resource in a service which run them synchronuously (using $timeout) and inject that service in app.run()? – asgoth Dec 31 '12 at 11:00
  • Actually, I don't think promises are broken in any sense at all, I think they're great. What I have in mind is that, my application strictly depends on a data which I expect to be loaded at initialization; I can set a promise and initialize main controller in the `then` on the promise. But since I do need that before everything, I don't want to use callbacks in my controller just for initialization, it is not elegant at all. That's what Dependency Injector is for. – Umur Kontacı Dec 31 '12 at 11:38
  • 1
    If you run the `$timer` from within the `run`, it'll maintain it's state through `.call()`, so I would think that's probably the most elegant. Wait for the promise to signal to `run()` they're resolved and it cancels the `$timer`. The docs seem to make that sound the way they intended it to work. – Jared Farrish Dec 31 '12 at 14:07
  • You might wanna check `$q.when()` to easily handle any mixed-state promise (resolved or not). – Olivier Jan 02 '13 at 03:01

2 Answers2

5

I've seen a similar problem. A somewhat elegant solution a team mate employed was a combination with RequireJS and it's domReady module:

define(['require', 'angular', 'app','routes', 'pendingServices'], 
      function (require, ng, app, pendingServices) {


  /* place operations that need to initialize prior to app start here
   * using the `run` function on the top-level  module
   */
  app.run(pendingServices.init)

  require(['domReady!'], function (document) {
      /* everything is loaded...go! */
      ng.bootstrap(document, ['mainModule']);
  });

});

In the init method you can do all the preloading (and wait for the desired promises). I'm interested to hear other solutions of course.

iwein
  • 25,788
  • 10
  • 70
  • 111
  • Why use domReady? angular has its own angular.element(document).ready() function (which is a wrapper around jQueryLite). – asgoth Dec 31 '12 at 12:55
  • domReady isn't necessary, but with RequireJS it's a bit neater, that's all. – iwein Dec 31 '12 at 13:31
  • But how will this work? Is 'pendingServices' a module using $timeout to load its content? – asgoth Dec 31 '12 at 13:44
  • It uses $q, but it could be made to work using $timeout. I'll add some more details to the question, it's still unclear. – iwein Dec 31 '12 at 14:07
  • delaying the applications bootstrap seems to be a decent workaround; at least for this case, yet still I'd love to use DI for that. I'll leave the question open for more time, maybe a better solution would come up. – Umur Kontacı Jan 02 '13 at 06:30
  • @fastreload let's hope indeed that a better solution comes up. There's some work to do on the frameworks too I think. – iwein Jan 02 '13 at 08:02
1

Just thinking out load here, but how about only declaring 1 'catch all' route to begin, and in that route provider, hold the loading of the route until you have done everything you need. (using resolve and promises).

Then, when you're done, register the remaining routes, and reload the original route. This time, a more specific handler should be registered and it will bypass your 'catch all' initializer.

What do you think, any issues?

mcampster
  • 47
  • 5