Angular 2不同组件具有相同路线

Max*_*ink 7 angular2-routing angular

我有一个应用程序,它需要将经过身份验证的用户和来宾用户的组件分开。但是我需要,两个组件都将通过“ /”路由加载。我写

{
    path: 'desktop',
    loadChildren: 'app/member/member.module#MemberModule',
    canActivate: [LoggedInGuard],
},
{
    path: '',
    loadChildren: 'app/guest/guest.module#GuestModule',
    canActivate: [GuestGuard],
},
Run Code Online (Sandbox Code Playgroud)

而且有效。但是,如何使两个组件都通过相同的网址加载?我曾尝试path: ''为会员的模块路由编写程序,但是未执行第二个路由器规则。这是警卫代码:

LoggedInGuard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if(this.sessionService.isLoggedIn()) {
        return true;
    } else {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

GuestGuard:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if(!this.sessionService.isLoggedIn()) {
        return true;
    } else {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个小矮人:http ://embed.plnkr.co/VaiibEVGE79QU8toWSg6/

我应该如何正确做?谢谢

Ant*_*kov 8

所以我终于能够做到这一点。事情是Angular使用先匹配策略,因此我们需要以警卫类型匹配路由,以确保正确的路由和正确的模块被匹配。

首先,我们需要为路线添加自定义匹配器,这些匹配器仅在我们想要的条件下匹配(例如,用户类型)。

{
 path: 'samePath',
 matcher: firstMatcher,
 loadChildren: '../first/first.module#FirstModule'
},
{
 path: 'samePath',
 matcher: secondMatcher,
 loadChildren: '../second/second.module#SecondModule'
}
Run Code Online (Sandbox Code Playgroud)

匹配器代码是这样的:在这里,我从AppModule中注入了AuthService服务,并检查了用户键入的内容。因此可以根据用户类型匹配路由。

import { applicationInjector } from '../../main';

export function firstMatcher (url: UrlSegment[]) {
  const auth =  applicationInjector.get(AuthService);
  return auth.isUserType('admin') ? ({consumed: [url[0]]}) : null;
}
Run Code Online (Sandbox Code Playgroud)

现在,我们只需要applicationInjector在主模块中创建,就可以在匹配器功能中注入服务。

export let applicationInjector: Injector;

platformBrowserDynamic().bootstrapModule(AppModule).then((componentRef) => {
  applicationInjector = componentRef.injector;
})
Run Code Online (Sandbox Code Playgroud)

  • 我想补充一点,使用匹配器时不能指定`path`,因为它会给出编译器错误;无论如何,它都是多余的,因为所有通过“path”接收的路径信息都是通过匹配器的“url”参数传递的。这个答案拯救了我的一天! (2认同)

Ger*_*ros 7

您可以通过使用 Angular 的 useFactory 提供程序提供 RouterModule 的 ROUTES 来使用处理应该加载哪个模块的模块。

代码可能是这样的。

// HandlerModule

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    RouterModule
  ],
  providers: [
    {
      provide: ROUTES,
      useFactory: configHandlerRoutes,
      deps: [SessionService],
      multi: true
    }
  ]
})


export class HandlerModule {}

export function configHandlerRoutes(sessionService: SessionService) {
  let routes: Routes = [];
  if (sessionService.isLoggedIn()) {
    routes = [
      {
        path: '', loadChildren: () => import('app/member/member.module').then(mod => mod.MemberModule)
      }
    ];
  } else {
    routes = [
      {
        path: '', loadChildren: () => import(app/guest/guest.module).then(mod => mod.GuestModule)
      }
    ];
  }
  return routes;
}
Run Code Online (Sandbox Code Playgroud)

然后在您的 AppRoutingModule 中,路径 '' 的模块将成为 HandlerModule:

// AppRoutingModule

 {
    path: '',
    loadChildren: () => import('app/handler/handler.module').then(mod => mod.HandlerModule)
}
Run Code Online (Sandbox Code Playgroud)

在 SessionService 之后,当提供方法 isLoggedIn 的值发生变化时,您必须更新 Router.config,因为应用程序只会加载第一次加载的页面(模块)。这是因为 HandlerModule 中 useFactory 提供者使用的函数“configHandlerRoutes”仅在我们第一次导航到“”路径时执行,之后Angular Router已经知道他必须加载哪个模块。

总之,在 SessionService 中,您必须执行以下操作:

  export class SessionService {
  private loggedIn: boolean;
  constructor(private router: Router) {
    this.loggedIn = false;
  }

  public isLoggedIn(): boolean {
    return this.loggedIn;
  }

  public setLoggedIn(value: boolean): void {
    const previous = this.loggedIn;
    this.loggedIn = value;
    if (previous === this.loggedIn) {
      return;
    }
    const i = this.router.config.findIndex(x => x.path === '');
    this.router.config.splice(i, 1);
    this.router.config.push(
      {path: '', loadChildren: () => import('app/handler/handler.module').then(mod => mod.HandlerModule)}
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

就是这样。

如果你想要另一个参考,这里有一篇他们使用相同方法的文章:https : //medium.com/@german.quinteros/angular-use-the-same-route-path-for-different-modules-or-components -11db75cac455


San*_*was -3

实现此目的的一种方法是根据用户是否登录来路由到适当的区域。

(即无论您打开空白路线还是访客路线,都会适当重定向,并且后退按钮不起作用)

路线:

{
    path: '',
    loadChildren: 'app/member/member.module#MemberModule',
    canActivate: [LoggedInGuard],
},
{
    path: 'guest',
    loadChildren: 'app/guest/guest.module#GuestModule',
    canActivate: [GuestGuard],
}
Run Code Online (Sandbox Code Playgroud)

登录卫士: :

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if(this.sessionService.isLoggedIn()) {
        return true;
    } else {
        // route to 'guest' if not logged in
        this.router.navigate(['/guest'], { replaceUrl: true });
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

GuestGuard (如果登录,会自动路由到 MemberComponent)

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    if(this.sessionService.isLoggedIn()) {
        // route to member area if already logged in
        this.router.navigate(['/'], { replaceUrl: true });
        return false;
    } else {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)