Compreendendo o contexto de injeção angular

May 02 2023
Angular introduziu a função inject() em versões recentes, o que nos permite obter uma referência a um provedor de maneira funcional, em vez de usar o método Injector.get().

Angular introduziu a inject()função em versões recentes, o que nos permite obter uma referência a um provedor de forma funcional ao invés de usar o Injector.get()método. No entanto, se você o usou ou uma biblioteca que o usa sob o capô, pode ter encontrado o seguinte erro:

inject() must be called from an injection context 
such as a constructor, a factory function, a field initializer, 
or a function used with `runInInjectionContext`.

Angular tem duas variáveis ​​globais que podem conter um injectorem um determinado ponto no tempo: uma para an Injectore outra para NodeInjector. Aqui estão os trechos de código para ambos:

let _currentInjector = undefined;

export function getCurrentInjector() {
  return _currentInjector;
}

export function setCurrentInjector(injector: Injector|undefined|null {
  const former = _currentInjector;
  _currentInjector = injector;
  return former;
}
let _injectImplementation

export function getInjectImplementation() {
  return _injectImplementation;
}

export function assertInInjectionContext(debugFn: Function): void {
  if (!getInjectImplementation() && !getCurrentInjector()) {
    throw new RuntimeError(
        RuntimeErrorCode.MISSING_INJECTION_CONTEXT,
        ngDevMode &&
            (debugFn.name +
             '() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`'));
  }
}

import {
  ElementRef,
  assertInInjectionContext,
  inject,
} from '@angular/core';

export function injectNativeElement<T extends Element>(): T {
  assertInInjectionContext(injectNativeElement);

  return inject(ElementRef).nativeElement;
}

  • Na factoryfunção especificada para um InjectionToken:
  • export const FOO = new InjectionToken('FOO', {
      factory() {
        const value = inject(SOME_PROVIDER);
        return ...
      },
    });
    

    
    @Component({
      providers: [
        {
          provide: FOO,
          useFactory() {
            const value = inject(SOME_PROVIDER);
            return ...
          },
        },
      ]
    })
    export class FooComponent {}
    

    @Component({})
    export class FooComponent {
      foo = inject(FOO);
    
      constructor(private ngZone: NgZone = inject(NgZone)) {
        const bar = inject(BAR);
      }
    }
    

  • Dentro de uma função que é executada usando a runInInjectionContextfunção:
  • import { runInInjectionContext } from '@angular/core';
    
    export class FooComponent {
      ngOnInit() {
        runInInjectionContext(this.injector, () => {
          console.log(
            'I can access the NodeInjector using inject()',
            inject(ElementRef)
          );
        })
    }
    

Siga-me no Medium ou Twitter para ler mais sobre Angular e JS!