Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

canActivate Dependant on Parent Route Resolve

Tags:

angular

I have routes setup like so:

export const APP_ROUTES: Routes = [
    {
        path: '',
        resolve: {
            user: CurrentUserResolver
        },
        children: [
            {
                path: ':sectionKey',
                canActivate: [SectionAccessGuard],
                children: [
                    {
                        path: 'dashboard',
                        component: DashboardComponent
                    }
                ]
            }
        ]
    }
]

Where the parent route will retrieve the user via a HTTP call, and I'd like my sub-route :sectionKey to only be activated if the current user has access to it. The issue is, it appears my canActivate SectionAccessGuard is called prior to the snapshot being fully populated:

@Injectable()
export default class SectionAccessGuard implements CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        console.log(route.data);
        console.log(route);
        return true;
    }
}

In the console, the first entry will have nothing; however, the 2nd entry will eventually have the user field populated.

I know the canActivate method can return an Observable<boolean> as well, but I don't see any hooks on how to wait until the resolve completes.

What am I missing here? I feel like this should be pretty straight forward. I'm currently using angular v4.0.0-rc.2

like image 345
John Avatar asked Mar 08 '17 18:03

John


Video Answer


1 Answers

It's been about 8 months since I posted this so I'll give an update on where we ended up:

Storing data in the router through resolves started to become very awkward depending on where the component was (this.route.parent.parent.parent.data.user), so we're no longer using resolves, and instead using NgRx to store that kind of information.

Our guards then are in charge of triggering the fetching of the data, as well as waiting until it's complete. Something like this:

@Injectable()
export class AuthenticationGuard implements CanActivate {
    constructor(private router: Router, private store: Store<ApplicationState>) { }

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        this.store.dispatch(new AuthenticateAction());

        return this.store
            .select('auth')
            .filter((s) => !!s && !s.authenticating)
            .map((s) => s.authenticated)
            .take(1);
    }
}

Where there are a couple flags in the state (authenticating and authenticated) that tell the guard where we're at in the process.

like image 78
John Avatar answered Oct 02 '22 10:10

John