Tengo rutas configuradas así:
export const APP_ROUTES: Routes = [ { path: '', resolve: { user: CurrentUserResolver }, children: [ { path: ':sectionKey', canActivate: [SectionAccessGuard], children: [ { path: 'dashboard', component: DashboardComponent } ] } ] } ] Donde la ruta principal recuperará al usuario a través de una llamada HTTP, y me gustaría que mi :sectionKey solo se active si el usuario actual tiene acceso a ella. El problema es que parece que mi canActivate SectionAccessGuard se llama antes de que la instantánea se llene por completo:
@Injectable() export default class SectionAccessGuard implements CanActivate { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { console.log(route.data); console.log(route); return true; } } En la consola, la primera entrada no tendrá nada; sin embargo, la segunda entrada eventualmente tendrá el campo de user completado.
Sé que el método canActivate puede devolver un Observable<boolean> , pero no veo ningún enlace sobre cómo esperar hasta que se complete la resolución.
¿Que me estoy perdiendo aqui? Siento que esto debería ser bastante sencillo. Actualmente estoy usando angular v4.0.0-rc.2
Han pasado alrededor de 8 meses desde que publiqué esto, así que daré una actualización sobre dónde terminamos:
El almacenamiento de datos en el enrutador a través de resoluciones comenzó a volverse muy incómodo dependiendo de dónde estaba el componente ( this.route.parent.parent.parent.data.user ), por lo que ya no estamos usando resoluciones, y en su lugar usamos NgRx para almacenar eso. tipo de información
Nuestros guardias están a cargo de activar la obtención de los datos, así como de esperar hasta que se complete. Algo como esto:
@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); } }Donde hay un par de banderas en el estado (autenticación y autenticación) que le dicen al guardia dónde estamos en el proceso.
No estoy seguro de si es posible hacer que el guardia funcione después de que se complete el resolutor, pero intentaría mover el código del resolutor a canActivate().
Cuando el observable que obtiene la información del usuario actual devuelve los datos, aplique su lógica para verificar si el usuario puede navegar a la ruta.
También estoy luchando con esto y me gustaría ver más documentación sobre esto del equipo de Angular. Parece que canActivate no espera para comenzar a ejecutarse hasta que finaliza el padre, pero resolve sí.
Puede cambiar su código de activación a otra resolución, porque una resolución secundaria espera una resolución principal. Si se cambia para resolver, tendrá acceso al usuario a través de route.parent.data.user y luego puede hacer una llamada a router.navigate para salir de la sección si el usuario no está autorizado.
Otro enfoque es configurar un servicio que se pueda inyectar tanto en resolve guard como en canActivate guard. Tendría que configurar un observable desde la protección de resolución y suscribirse a ella en la protección de canActivate.