web-dev-qa-db-fra.com

Obtenir une instance de service sans injection de constructeur

J'ai un service @Injectable Défini dans le bootstrap. Je veux obtenir l'instance du service sans utiliser l'injection de constructeur. J'ai essayé d'utiliser ReflectiveInjector.resolveAndCreate Mais cela semble créer une nouvelle instance.

La raison pour laquelle j'essaie de faire est que j'ai un composant de base dérivé de nombreux composants. Maintenant, je dois accéder à un service, mais je ne veux pas l'ajouter au ctor, car je ne veux pas l'injecter sur tous les composants dérivés.

TLDR: j'ai besoin d'une ServiceLocator.GetInstance<T>()

UPDATE: Code mis à jour pour RC5 +: enregistrement d'une instance d'injecteur à utiliser dans des composants

55
dstr

Oui, ReflectiveInjector.resolveAndCreate() crée une nouvelle instance d'injecteur non connectée.

Vous pouvez injecter une instance de Angulars Injector et en obtenir l’instance souhaitée en utilisant

constructor(private injector:Injector) {
  injector.get(MyService);
}

Vous pouvez également stocker Injector dans une variable globale et utiliser cette instance d'injecteur pour acquérir les instances fournies, par exemple comme expliqué dans https://github.com/angular/angular/issues/4112# issuecomment-153811572

56

Dans le Angular mis à jour où les ngModules sont utilisés, vous pouvez créer une variable disponible n'importe où dans le code:

export let AppInjector: Injector;

export class AppModule {
  constructor(private injector: Injector) {
    AppInjector = this.injector;
  }
}
26
Elias Rezer

Une autre approche consisterait à définir un décorateur personnalisé (un CustomInjectable pour définir les métadonnées pour l'injection de dépendance:

export function CustomComponent(annotation: any) {
  return function (target: Function) {

    // DI configuration
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);

    Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);

    // Component annotations / metadata
    var annotations = Reflect.getOwnMetadata('annotations', target);
    annotations = annotations || [];
    annotations.Push(annotation);
    Reflect.defineMetadata('annotations', annotations, target);
  }
}

Il utilisera les métadonnées du constructeur parent au lieu de ses propres. Vous pouvez l'utiliser sur la classe enfant:

@Injectable()
export class SomeService {
  constructor(protected http:Http) {
  }
}

@Component()
export class BaseComponent {
  constructor(private service:SomeService) {
  }
}

@CustomComponent({
  (...)
})
export class TestComponent extends BaseComponent {
  constructor() {
    super(arguments);
  }

  test() {
    console.log('http = '+this.http);
  }
}

Voir cette question pour plus de détails:

5
Thierry Templier