Angular 2: Inject a dependency into @CanActivate?

丶灬走出姿态 提交于 2019-11-30 12:43:52

Most solutions here will present problems with loading sub-dependencies from elsewhere in the hierarchy, because they create a new injector. Also, this results in additional (non-shared) services being instanced. I recommend following the pattern provided by Brandon in https://github.com/angular/angular/issues/4112

He references this Plunk: http://plnkr.co/edit/SF8gsYN1SvmUbkosHjqQ?p=preview

Its main idea is a singleton injector, which he saves when the app initializes. This provides access to the root dependencies you already have configured, and further allows your services to be shared as a singleton as they were probably intended:

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);
});

You have to inject it using injector. Just a quick copy paste from a project I'm doing:

@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_PROVIDERS you have to pass along if your service is for example injecting the HTTP service in the constructor.

I use it to put an observable on the params of the next object. And the next object is your next "Component/state":

@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);
  });

})

The PropertiesService calls a backend and returns an Observable that represents the data with properties

I don't know if its the best way, but these guys do it by extending and using its own <router-outlet> and override the CanActivate method:

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/

Also you could use routerOnActivate instead.

https://angular.io/docs/js/latest/api/router/OnActivate-interface.html I hope this helps.

Here (https://gist.github.com/clemcke/c5902028a1b0934b03d9) is how to test the addInjector() solution that @shannon references:

beforeEachProviders(()=>[PERSON_SERVICE_PROVIDERS]);

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

Angular 2.0 final solution:

Since we now define a separate class which implements CanActivate, that class can be @Injectable, and another dependency can be provided in its constructor as per this answer.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!