【问题标题】:Angular 2: Inject a dependency into @CanActivate?Angular 2:将依赖项注入@CanActivate?
【发布时间】:2016-04-15 04:43:34
【问题描述】:

在 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

【问题讨论】:

标签: angular angular2-routing


【解决方案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-between/

您也可以改用routerOnActivate

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

【讨论】:

  • 谢谢,我之前也遇到过,但我认为路由 API 从那时起发生了很大变化;我无法让他们的示例正常工作。
  • 我明白了,你为什么不试试routerOnActivate呢?您仍然可以避免组件被实例化,但您确实可以以某种方式访问​​其注入的属性。 angular.io/docs/js/latest/api/router/OnActivate-interface.html
【解决方案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,它表示具有属性的数据

【讨论】:

  • 这样你会得到一个YourService 的新实例,不是吗。这可能不是所希望的。一种解决方法是使用静态字段从 AppComponent 存储注入器,然后在 @CanActivate() 中使用此注入器,而不是创建一个新的注入器。
  • 是的,我猜您通常不希望每次访问新的服务实例。您可能希望缓存从服务器获取的值。如果您不需要它,那么您的解决方案当然应该可以正常工作。
  • 从 Angular 的角度来看没有必要。这仅取决于您作为软件架构师的期望。只要您使用相同的注射器,它就是一个单例。在您的回答中,您创建了一个新的注入器,它有自己的单例。
  • 我不明白“如何以及何时在 Angular2 中为服务实现一个类”——当然总是这样。我想指出的是,bootstrap(AppComponent, [YourService]) 创建了一个注入器,Injector.resolveAndCreate([HTTP_PROVIDERS, YourService]) 创建了另一个注入器,其中两者都有一个单例(在您的应用程序中总计有 2 个实例)。
  • 啊哈,有道理! :) 我还在学习过程中。但仍然:如何在 @CanActivate 注释中访问它
【解决方案3】:

这里的大多数解决方案都会出现从层次结构中的其他位置加载子依赖项的问题,因为它们会创建一个新的注入器。此外,这会导致附加(非共享)服务被实例化。我建议遵循 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);
});

【讨论】:

  • 我试过了,但我的路由参数没有解析。让 routeParams: RouteParams= injector.get(RouteParams);
【解决方案4】:

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

beforeEachProviders(()=>[PERSON_SERVICE_PROVIDERS]);

beforeEach(inject([PersonService],()=>{
  let injector = Injector.resolveAndCreate([PERSON_SERVICE_PROVIDERS]);
  appInjector(injector);
}));

【讨论】:

    【解决方案5】:

    Angular 2.0 最终解决方案:

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

    【讨论】:

      猜你喜欢
      • 2016-02-15
      • 1970-01-01
      • 2016-10-20
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 2016-10-23
      相关资源
      最近更新 更多