Angular2 - 扩展路由器和Observable

时间:2016-06-17 19:14:49

标签: javascript node.js login angular angular2-router

在使用路由器模块v 3.0.0.6alpha的angular2 rc2中,我扩展了RouterOulet以检查用户是否在登录之前登录。所以这是代码:

@Directive({
    selector: 'router-outlet'
})

export class LoggedInRouterOutlet extends RouterOutlet 
{
    publicRoutes: Array<string>;
    private parentOutletMap: RouterOutletMap;
    private userService: UserService;
    private parentRouter: Router;

    constructor(
        parentOutletMap: RouterOutletMap,
        _location: ViewContainerRef,
        @Attribute('name') name: string,
        userService: UserService,
        parentRouter: Router
    ) { 
        super(parentOutletMap, _location, name);

        this.parentRouter = parentRouter;
        this.parentOutletMap = parentOutletMap;
        this.userService = userService;
        this.publicRoutes = [
            'public', 
            'login'
        ];
    }

    activate(factory: ComponentFactory<any>, activatedRoute: ActivatedRoute, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap) 
    {
        if (this._canActivate(factory.selector)) { 
            return super.activate(factory, activatedRoute, providers, outletMap); 
        }

        this.parentRouter.navigate(['/login']);
    }

    _canActivate(url) {
        return this.publicRoutes.indexOf(url) !== -1 || this.userService.isLoggedIn()
    }
}

userService.isLoggedIn()必须返回一个布尔值。我的问题是:如何调整我的代码进行http调用以检查用户是否已登录?因为如果isLoggedIn方法返回一个可观察对象,并且我订阅它,我就无法在父函数中返回结果。

1 个答案:

答案 0 :(得分:8)

请注意,OutletRouter的activate方法的结果已更改。

<强> @角/路由器弃用

activate(nextInstruction: ComponentInstruction) : Promise<any>

<强> @角/路由器

activate(factory: ComponentFactory<any>, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap) : ComponentRef<any>

不再是Promise或Observable。新的路由器实现带来了一些我认为更清洁的解决方案:Guards。

  

后卫的返回值控制着路由器的行为:

     

如果返回true,导航过程会在返回时继续   false,导航过程停止,用户保持警惕   也可以告诉路由器在其他地方导航,有效取消   当前导航。

     

守卫可能会同步返回其布尔答案。但在很多方面   在这种情况下,警卫不能同步产生答案。守卫   可以向用户询问问题,保存对服务器的更改或获取   新鲜数据。这些都是异步操作。

     

因此,路由保护可以返回一个Observable和   路由器将等待observable解析为true或`false。

您可以创建auth.guard.ts:

import { Injectable }             from '@angular/core';
import { CanActivate,
         Router,
         ActivatedRouteSnapshot,
         RouterStateSnapshot }    from '@angular/router';
import { UserService }            from './user.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private userService: UserService, private router: Router) {}

  canActivate(
    // Not using but worth knowing about
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ) {
    return this.userService.isLoggedIn();
  }
}

现在确保你的isLoggedIn返回Observable(或Promise - 同时尝试Angular2 Reference为not ready yet)。在我的情况下,API以格式返回JSON:{success:true / false}。

public isLoggedIn() : Observable<boolean> | boolean {
    let router: Router = this.router;
    let obs;

    try {
        obs = this.authHttp.get('/api/check/logged')
            .map(result => result.json())
            .map(resultJson => (resultJson && resultJson.success));

    } catch (err) {
        obs = Observable.of(false);
    }

    return obs
        .map(success => {
             // navigate to login page
             if (!success)
                 router.navigate(['/auth/login']);

             return success;
        });
}

然后只需修改您的RouterConfig数组:

{ path: '/secret', component: SercetComponent, canActivate: [AuthGuard] }

另请参阅Angular2 Developer Guide