7

This question, among many others, shows to use a controller-level resolve for async data that needs to be loaded before an application is started.

I have a lot of controllers, with all separately defined routes in each module... using resolve would be ridiculous to me if they all depend on the data. I also have directives which depend on the data (auto-complete search, etc).

Isn't there a better way to do: "load data (using an angular service) before each controller is shown"? I need the application to load, async fetch the data, and I use ng-show with some rootScope data that either shows loading or the controller template. I tried putting it in app.run, but couldn't get it to work properly...anything asynchronous in that block seems to wonk up the application.

Help?

3 Answers 3

1

Here's what I did. I'm not a huge fan of this solution, but it's the best I've been able to come up with so far.

First of all, you can have multiple resolves in each route, like so:

resolve: {
  UserAccount: app.resolves('UserAccount'),
  Posts: app.resolves('Posts')
}

Since you can't inject application services into the config block, I created a big old object in another file that contains shortcuts to my services:

app.resolves = (function(){
  // Resolves allow us to use `deferred`s to only
  // load our template after the data it requires
  // has been provided by the server.
  var resolve = {};

  resolve.UserAccount =
  ['Users', function (Users) {
     return Users.fetchActive();
  }];

  resolve.Posts =
  ['Posts', function(Posts) {
     return Posts.getAllPosts();
  }];

  // Public API
  // @param string name
  return function (name) {
    return resolve[name]
  };
})();
Sign up to request clarification or add additional context in comments.

4 Comments

Is there not a way to specific an "app" resolve? If I have 15 different controllers, I only want to specify a "resolve" object once (app...resolve: mydata), not that same block 15 times.
Maybe you could try something like this: jsfiddle.net/N9eAz I haven't tested it beyond there not being any javascript errors. Your app.resolveUsers() function should return a promise, or an object with each member being a promise. As long as it's in your app config directly after your route declarations I would think it would do the trick.
Actually, try this one: jsfiddle.net/JJEHs This will preserve any existing resolves on a route. Just make sure you're declaring them in the object syntax like my route example.
I like that last one!
1

I know this question is old, but since there's no accepted answer, nor a clean one, I am attempting to solve this too.

The lack of having a resolve state per app was bugging me for a while now, and this is the solution I finally came up with: http://jsfiddle.net/gabrielcatalin/cvyq0oys/

In short, I created an Angular Module Enhancer(decorator), which supports 2 more methods: resolve() and ready(). The AngularEnhancer snippet just needs to be loaded after the angular.js has loaded and before the implementation, like so:

<script type="text/javascript" src="angular.js">
<script type="text/javascript" src="angularEnhancer.js">
<script type="text/javascript" src="main.js">

This is how an implementation will look:

angular.module('myApp', [])
    .ready(function() {
        alert('The app is ready to be used!');
    })
    .resolve(['$q', function ($q) {
        // The resolve can wait for a promise to be resolved
        var differed = $q.defer();

        setTimeout(function() {
            differed.resolve();    
        }, 1000);

        return differed.promise;

        // Or a true value
        // return true;

        // Or even a truish value
        // return 'value';
    }])
    .ready(function() {
        // The order of where the ready() appear doesn't matter
        alert('This is just another alert to show that it can have as many as possible!');
    }); 

and the html:

<body>
    <div ng-if="!appReady" class="splash-screen">This is just the splash screen!</div>
    <div ng-if="appReady">Welcome to the app!</div>

    <script>
        angular.element(document).ready(function() {
            angular.bootstrap(document, ['myApp']);
        });
    </script>
</body>

Hope to see some comments from you guys!

Comments

0

I think that, since there's no obvious way to made app-level resolve configuration, the best thing you can do is actually modify the $routeProvider capabilities using a decorator. This way you can check if a resolve config is set on each application route and add/merge a special resolve promise that will either load async data or continue with the needed data, with the bonus of having a central point to test or modify when you need.

I'm struggling with this same issue right now. I'll try to make a generic/reusable code here and post my solution very soon on GitHub. I'll try to update this answer with a proper example here as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.