message: fix(common): avoid interacting with a destroyed injector
  The NgOptimizedImage directive was previously trying to use an
  already destroyed injector in the ngOnDestroy callback. This fix
  pre-injects necessery tokens so no injector calls are done
  in the destroy process.
  PR Close
diff: @@ -169,6 +169,9 @@ export class NgOptimizedImage implements OnInit, OnChanges, OnDestroy {
  private imgElement: HTMLImageElement = inject(ElementRef).nativeElement;
  private injector = inject(Injector);
  + // a LCP image observer - should be injected only in the dev mode
  + private lcpObserver = ngDevMode ? this.injector.get(LCPImageObserver) : null;
  +
  /**
  * Calculate the rewritten `src` once and store it.
  * This is needed to avoid repetitive calculations and make sure the directive cleanup in the
  @@ -277,10 +280,12 @@ export class NgOptimizedImage implements OnInit, OnChanges, OnDestroy {
  // Monitor whether an image is an LCP element only in case
  // the `priority` attribute is missing. Otherwise, an image
  // has the necessary settings and no extra checks are required.
  - invokeLCPImageObserverCallback(
  - this.injector,
  - (observer: LCPImageObserver) =>
  - observer.registerImage(this.getRewrittenSrc(), this.rawSrc));
  + if (this.lcpObserver !== null) {
  + const ngZone = this.injector.get(NgZone);
  + ngZone.runOutsideAngular(() => {
  + this.lcpObserver!.registerImage(this.getRewrittenSrc(), this.rawSrc);
  + });
  + }
  }
  }
  this.setHostAttributes();
  @@ -344,10 +349,8 @@ export class NgOptimizedImage implements OnInit, OnChanges, OnDestroy {
  ngOnDestroy() {
  if (ngDevMode) {
  - if (!this.priority && this._renderedSrc !== null) {
  - invokeLCPImageObserverCallback(
  - this.injector,
  - (observer: LCPImageObserver) => observer.unregisterImage(this._renderedSrc!));
  + if (!this.priority && this._renderedSrc !== null && this.lcpObserver !== null) {
  + this.lcpObserver.unregisterImage(this._renderedSrc);
  }
  }
  }
  @@ -373,24 +376,6 @@ function inputToBoolean(value: unknown): boolean {
  return value != null && `${value}` !== 'false';
  }
  -/**
  - * Invokes a function, passing an instance of the `LCPImageObserver` as an argument.
  - *
  - * Notes:
  - * - the `LCPImageObserver` is a tree-shakable provider, provided in 'root',
  - * thus it's a singleton within this application
  - * - the process of `LCPImageObserver` creation and an actual operation are invoked outside of the
  - * NgZone to make sure none of the calls inside the `LCPImageObserver` class trigger unnecessary
  - * change detection
  - */
  -function invokeLCPImageObserverCallback(
  - injector: Injector, operation: (observer: LCPImageObserver) => void): void {
  - const ngZone = injector.get(NgZone);
  - return ngZone.runOutsideAngular(() => {
  - const observer = injector.get(LCPImageObserver);
  - operation(observer);
  - });
  -}
  /***** Assert functions *****/
  