0

I have an AngularJS application where I need some basic information, that I get from the server via async call, before I can continue loading or processing the page.

I know there are other similar questions to this, but all of the others I found are related to loading a data before initializing an specific part (directive, controller, factory, etc..).

What I want is to use this data in multiple places, doesn't matter if it's a component, directive, etc. Because If I initialize in one of them without the data, I will not be able to proceed.

For example: I have a div in my footer where I show a location using Google Maps, so I need the location before I can run (currently inside a directive) the code to place the Google Maps. I made a plunker to illustrate this problem (without the fix mentioned below).

https://plnkr.co/edit/2RkansVp3NQNx3Tb4lMD?p=preview


What I did

I could solve this problem by using ui-router resolve, although it doesn't seem to be the proper way to do this. I'm using a "blank" state just to resolve the data and moved the basic elements from the index.html to this app.html page, which would be my index, but since I need to load the data, I had to move.

This is my code:

.state('app', {
    abstract: true,
    views: {
        'main': {
            templateUrl: 'view/app.html'
        }
    },
    resolve: {
        dataLoad: function($q, api, store) {
            var promises = {
                //[..loading more data..]
                location: api.request('getLocation')
            }

            return $q.all(promises).then(function(resolve){
                //[..resolving more data..]
                return store.location = resolve.location;
            })
        }
    }
})
.state('home', {
    parent: 'app',
    url: '/Home',
    views: {
        'app': {
            templateUrl: 'view/home.html'
        }
    }
})

index.html

<body ui-view="main"></body>

app.html

<header>[...]</header>

<main ui-view="app"></main>

<footer>[...]</footer>

This way I can initiate all the data properly, since the app.html will load only after the resolve on the parent app state.

But, as you can see, my index.html is completely empty and I had to create the app.html just to go around this situation.


Is this the way to go? Or is there a better/correct method to load the data before I initiate my application, or to load in other area (.run, for example) and wait until all the data is resolved?

celsomtrindade
  • 4,501
  • 18
  • 61
  • 116
  • This data you need to load is loaded just once ... or it needs to be retrieved more than once (for instance if it changes in time and then your need to retrieve it again)? – lealceldeiro Mar 02 '17 at 22:34
  • @lealceldeiro just once. The data may change, but only if the user change by himself, which is not something done frequently. – celsomtrindade Mar 02 '17 at 22:36
  • According to [the documentation for resolve](https://github.com/angular-ui/ui-router/wiki#resolve) your state will not be entered into until the promises returned by the resolve call are resolved. I do note that your comments indicate you're "loading more data" inside the resolution of your `$q.all` call, but not returning a promise from that. If that's the case, you just need to return another promise from that call once you have all of the data. You might also look into nested states and put the `resolve` in a "root" state, then the states which use the data underneath, like "root.home"... – Heretic Monkey Mar 02 '17 at 22:59
  • @MikeMcCaughan I understand this concept. Maybe i just wrote wrong, but all the data being loaded is resolved properly. If I do the way I showed, it works fine. But the problem is that I need to create a new file to place the content I usually place direct on the index, just to avoid these errors, where the data isn't ready yet. – celsomtrindade Mar 02 '17 at 23:03
  • Yeah, that's why I mention nested states. You shouldn't need to do anything with separate files, as long as you configure your states wisely. – Heretic Monkey Mar 02 '17 at 23:18
  • @MikeMcCaughan would you mind giving an example? Because I tried lots of ways to do it within the ui-router resolve, but not a way where I can call data from the server (async), wait until this data is ready an then start the application. – celsomtrindade Mar 02 '17 at 23:22
  • So, you'd still be starting the application before getting the data, but it wouldn't matter since your client wouldn't get anything before the router resolved the root state. I don't have the time to write up an example right now, but I think [the wiki on nested states](https://github.com/angular-ui/ui-router/wiki/Nested-States-%26-Nested-Views#what-do-child-states-inherit-from-parent-states) does a pretty good job of describing the flow of data. See if that helps. – Heretic Monkey Mar 02 '17 at 23:28
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/137146/discussion-between-celsomtrindade-and-mike-mccaughan). – celsomtrindade Mar 03 '17 at 12:08

0 Answers0