Angular 4 load data before initialize the application
Asked Answered
R

3

8

I'm trying to load some data before my application starts. The reason why I need to do it, is because some of the menu has restricted access based on some user condition, for example, based on the user location.

So if the user doesn't have a location yet or it's location isn't enabled to access certain view, I need to block it.


I tried to use Angular Resolve method, without success, this is what I did:

Resolve guard

// The apiService is my own service to make http calls to the server.
@Injectable()
export class AppResolveGuard implements Resolve<any> {
    constructor(
        private _api: ApiService,
        private _store: Store<IStoreInterface>,
    ) { }

    resolve(): any {
        return this._api.apiGet('loadData').subscribe(response => {
            this._store.dispatch({
                type: USER_FETCH_DATA,
                payload: response.usuario
            });

            return response;
        });
    }
}

Routing

export const routing = [
    {
        path: '', component: AppComponent, canActivateChild: [AuthGuard], resolve: {app: AppResolveGuard},
        children: [
            { path: 'home', component: HomeComponent },
            { path: 'company', canActivate: [LocationGuard], component: CompanyComponent },
        ]
    }
];

The AuthGuard is just going to check for a valid cookie session.

As you can see, the routing I'm trying to block access is the company routing. I'm able to prevent access when I first load another page, for example, if the first access is to the page home and then I navigate to the page company the validation works fine, because the user data and location is already avaliable.

However, if the first access is to the page company, it will block all users to navigate there, because at the time the LocationGuard try to validate the user location, the data isn't avaliable yet.

I also tried to replace Resolve with CanActivate, but it never enables the view after the data is avaliable, it stays on a blank page.

Receptacle answered 9/8, 2017 at 0:7 Comment(3)
try to look in to this one https://mcmap.net/q/1021450/-inject-http-manually-in-angular-4 basically you can call you api before you bootstrap AppModule and then you can pass/access that data up in your guardsAisha
@Kuncevic cant it be solved using the angular router? Because it's all linked with the store, etc..Receptacle
Then sounds like you cant do that before app initialize as you rely on store, etcAisha
R
0

I've found a workaround on this question.

I found a way to use canActivate. I had already tried to use .map() to return an Observable, but the key point is the .first() at the end, this is waht solved the issue.

I'll keep it open tho, because if there is a way to achieve the same result using Resolve, maybe it is better.

Receptacle answered 9/8, 2017 at 0:57 Comment(0)
M
12

A few things ...

Pre-fetching data before a page loads is a great use of a resolver.

Preventing access to a route is a great use of CanActivate.

Note however that the resolver only works AFTER all guards are checked. So your code will attempt to run the CanActivate before running the resolver.

enter image description here

Marquardt answered 9/8, 2017 at 0:58 Comment(4)
Hum.. So going with canActivate (like I'm commenting on my own answer here) is the way to go?Receptacle
I don't understand your requirements well enough. But one option is to add the resolve to the parent route and the canActivate onto the child routes. That way the resolve should execute before the child's canActivate's run.Marquardt
@Marquardt can you help me to locate where this schema is in the official documentation of Angular? I easily find the schema for component lifecycles but I don't reach to find the one you provided regarding guards and resolvers 😢.Tillandsia
It is somewhat discussed here: angular.io/guide/router-tutorial-toh#milestone-5-route-guards Is that what you are looking for?Marquardt
S
5

I think you can use APP_INITIALIZER to load data before application starts.

Check this article:

https://devblog.dymel.pl/2017/10/17/angular-preload/

Stun answered 20/4, 2018 at 4:2 Comment(0)
R
0

I've found a workaround on this question.

I found a way to use canActivate. I had already tried to use .map() to return an Observable, but the key point is the .first() at the end, this is waht solved the issue.

I'll keep it open tho, because if there is a way to achieve the same result using Resolve, maybe it is better.

Receptacle answered 9/8, 2017 at 0:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.