10

在 Angular 2 中,您可以@CanActivate为组件指定一个注释,您可以在其中确定该组件是否应该被激活。它不是接口的原因是因为在组件实例化之前调用了回调。问题是,我想不出一种方法将依赖项注入到该回调中。而且我需要我的服务来告诉我我是否登录(以及以谁登录)来确定是否允许路由到特定组件。

如何将依赖项注入 @CanActivate 回调?我正在使用 ES5,这不起作用:

app.ListsComponent = ng.router.CanActivate([
    app.SessionService,
    function(session, instruction) {
        console.log(session);
        return true;
    }
])(app.ListsComponent);

编辑:或者,我可以routerOnActivate在组件上使用生命周期事件,this.router.navigate如果用户不应该在那里,我可以使用它来将用户送走。缺点是它会破坏浏览器历史记录:如果每次您到达特定 URL 时我都会异步重定向您,您就不能非常有用地使用浏览器中的后退按钮。有没有办法router.navigate使用history.replaceState而不是history.pushState这种情况?

4

5 回答 5

7

这里的大多数解决方案都会出现从层次结构中的其他地方加载子依赖项的问题,因为它们创建了一个新的注入器。此外,这会导致附加(非共享)服务被实例化。我建议遵循 Brandon 在https://github.com/angular/angular/issues/4112中提供的模式

他引用了这个 Plunk:http ://plnkr.co/edit/SF8gsYN1SvmUbkosHjqQ?p=preview

它的主要思想是一个单例注入器,他在应用程序初始化时保存它。这提供了对您已经配置的根依赖项的访问,并进一步允许您的服务作为单例共享,因为它们可能是预期的:

import {Injector} from 'angular2/angular2';
let appInjectorRef: Injector;

export const appInjector = (injector?: Injector):Injector => {
    if (injector) {
      appInjectorRef = injector;
    }

    return appInjectorRef;
};

bootstrap([ServiceYouNeed]).then((appRef) => {
    // store a reference to the injector
    appInjector(appRef.injector);
});
于 2016-01-22T08:48:07.443 回答
2

您必须使用注射器注入它。只是从我正在做的项目中快速复制粘贴:

@CanActivate((next: ComponentInstruction, prev: ComponentInstruction) => {

  console.info('CanActivate hook! - can return boolean or Promise');

  var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, YourService]);
  var yourService = injector.get(YourService);
  // do something with yourService
  return new Promise(function(resolve, reject) {
      resolve(true);
  });

})

如果您的服务例如在构造函数中注入 HTTP 服务,则必须传递 HTTP_PROVIDERS。

我用它在下一个对象的参数上放置一个 observable。下一个对象是您的下一个“组件/状态”:

@CanActivate((next: ComponentInstruction, prev: ComponentInstruction) => {

  console.info('properties component CanActivate hook! - can return boolean or Promise');
  var injector = Injector.resolveAndCreate([HTTP_PROVIDERS, PropertiesService]);
  var propertiesService = injector.get(PropertiesService);
  return new Promise(function(resolve, reject) {
      next.params['properties'] = propertiesService.getProperties();
      resolve(true);
  });

})

PropertiesService 调用一个后端并返回一个 Observable,该 Observable 表示具有属性的数据

于 2016-01-12T10:31:48.970 回答
1

这里(https://gist.github.com/clemcke/c5902028a1b0934b03d9)是如何测试 @shannon 引用的 addInjector() 解决方案:

beforeEachProviders(()=>[PERSON_SERVICE_PROVIDERS]);

beforeEach(inject([PersonService],()=>{
  let injector = Injector.resolveAndCreate([PERSON_SERVICE_PROVIDERS]);
  appInjector(injector);
}));
于 2016-01-26T21:25:08.280 回答
1

我不知道这是否是最好的方法,但是这些人通过扩展和使用它自己的方法<router-outlet>并覆盖该CanActivate方法来做到这一点:

https://auth0.com/blog/2015/05/14/creating-your-first-real-world-angular-2-app-from-authentication-to-calling-an-api-and-everything-in-之间/

你也可以routerOnActivate改用。

https://angular.io/docs/js/latest/api/router/OnActivate-interface.html 我希望这会有所帮助。

于 2016-01-10T23:42:33.090 回答
0

Angular 2.0 最终解决方案:

由于我们现在定义了一个实现 的单独类CanActivate,因此该类可以是@Injectable,并且可以根据答案在其构造函数中提供另一个依赖项。

于 2016-10-14T15:36:05.117 回答