angularrxjsangular-reactive-forms

Angular: "Injector has already been destroyed."


Angular app with a reactive form suddenly started reporting this error:

RuntimeError: NG0205: Injector has already been destroyed.

It probably comes from my async validator that uses observables.

import * as rx from 'rxjs';

class myComponent {
  /** The form: select the filling device
   */
  form = new FormGroup({
    field: new FormControl<number>(0, {
        asyncValidators: [
            (control: AbstractControl): rx.Observable<ValidationErrors | null> => 
              this.observable$.pipe(
                rx.take(1),  // complete observable immediately
                //... validation ... //
            ),
    ]}),
  });

Solution

  • In my particular case, a form with asyncValidators was to blame: Angular did not properly unsubscribe from a hot observable that used rxjs.share().

    Use rx.takeUntil() to unsubscribe in time (thanks @ilya.chepurnoy):

    import * as rx from 'rxjs';
    
    class myComponent {
      /** The form: select the filling device
       */
      form = new FormGroup({
        field: new FormControl<number>(0, {
            asyncValidators: [
                (control: AbstractControl): rx.Observable<ValidationErrors | null> => 
                  this.observable$.pipe(
                    rx.take(1),  // complete observable immediately
                    //... validation ... //
                    rx.takeUntil(this.destroyed$), // the solution
                ),
        ]}),
      });
    
    
      // Observable that completes when the component is destroyed
      private destroyed$: ReplaySubject<boolean> = new rx.ReplaySubject(1);
    
      ngOnDestroy() {
        this.destroyed$.next(true);
        this.destroyed$.complete();
      }
    }
    

    Alternatively, use untilDestroyed(this) from ngneat/until-destroy, or the new takeUntilDestroyed()