#takeUntilDestroyed(this.destroyRef) error in ControlValueAccessor registerOnChange

10 messages · Page 1 of 1 (latest)

winter matrix
#

Hi guys,
we have a ControlValueAccessor component, which has another form inside of it, and we are sending the values from the nested form up to its parent.

In constructor we have private readonly destroyRef: DestroyRef,
and the registerOnChange looks like this:

registerOnChange(fn: any): void {
    this.translationsForm.valueChanges
      .pipe(
        map((translation: Translation) => {
          translation.translations.forEach(t => (t.content = t.content ? t.content : ''));
          return translation;
        }),
        takeUntilDestroyed(this.destroyRef)
      )
      .subscribe(fn);
  }

And when we navigate out of the route, so the component is destroyed, we get this error in console:

zone.js:177 Uncaught Error: NG0911: View has already been destroyed.
    at storeLViewOnDestroy (core.mjs:3180:15)
    at NodeInjectorDestroyRef.onDestroy (core.mjs:10593:9)
    at Observable._subscribe (rxjs-interop.mjs:27:41)
    at Observable._trySubscribe (Observable.js:37:25)
    at Observable.js:31:30
    at errorContext (errorContext.js:19:9)
    at Observable.subscribe (Observable.js:22:21)
    at takeUntil.js:7:29
    at SafeSubscriber.<anonymous> (lift.js:10:28)
    at Observable.js:26:30

I googled, I asked AIs, I looked everywhere, but I can't find anything about this specific bug. Can you tell me what are we doing wrong please?

quasi cradle
#

Hmmmm can you share more info? What are you doing with param for “registerOnChange”

winter matrix
#

I've posted the whole registerOnChange function, the param is in the subscribe. Can you be more specific about the "more info" please? I don't know what else to post. I have multiple takeUntilDestroyed() in constructor, and some takeUntilDestroyed(this.destroyRef) outside the constructor in the same component, and they all work without any problem. But this one in registerOnChange is problematic.

glacial loom
#

We have the same problem. I noticed it has to do with registerOnChange being called when the component is destroyed, something I was not aware of

#

So what i noticed is that, should you do something like so, you won't get thet "View is already destroyed" error

#
    if (!this.onChangeRegistered) {
      this.translationsForm.valueChanges.subscribe(
         ...
      this.onChangeRegistered = true
     }
   }
#

Not sure why though...

stone oyster
#

I don't quite get what you mean, why would you subscribe in there and not just in the constructor

#
constructor() {
  this.translationsForm.valueChanges.pipe(
    // ...
    takeUntilDestroyed()
  ).subscribe(value => this.onChange?.(value));
}

registerOnChange(fn: (value: T) => void) {
  this.onChange = fn;
}