Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular - error in template results in an infinite loop

Tags:

angular

Please consider the following code:

//our root app component
import {ChangeDetectionStrategy, Component, ErrorHandler, Injector, NgModule, ViewContainerRef} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {ToastModule, ToastsManager} from "ng2-toastr/ng2-toastr";

@Component({
  selector: 'my-app',
  template: `
    <div>
      name={{(test$|async).name}}
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class App {
  test$: Observable<{name:string}> = null;

  constructor(toastr: ToastsManager, viewContainerRef: ViewContainerRef) {
    toastr.setRootViewContainerRef(viewContainerRef);
  }
}

export class CustomErrorHandler extends ErrorHandler {
  constructor(private injector: Injector) { super(); }
  handleError(err: any): void {
    super.handleError(err);
    this.injector.get(ToastsManager).error(err.message);
  }
}

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, ToastModule.forRoot() ],
  declarations: [ App ],
  bootstrap: [ App ],
  providers: [
    { provide: ErrorHandler, useClass: CustomErrorHandler, deps: [Injector] }
  ]
})
export class AppModule {}

Also available as a Plunker here.

An error is intentionally triggered in the component template (test is undefined). The custom error handler kicks in, logs the error and tries to pop up an error toast. Not only doesn't the toast pop up, but also the application keeps logging over and over the original error. Digging a little seems to indicate that this is caused by the toaster's setTimeout function being called repeatedly. I have tried doing something similar with different toaster libraries but with the same result.

The expected behaviour is that the toast pop ups once and that the error is logged only once.

Any idea on how to achieve this?

like image 696
Spiff Avatar asked Feb 08 '18 20:02

Spiff


1 Answers

Throw the error at the end of handleError().

Source: https://github.com/scttcper/ngx-toastr/issues/564#issuecomment-419910273

This isn't an issue with ngx-toastr.

What is happening is that if there's something like a template error and you've "handled" the error, change detection will continue to run over and over causing the infinite loop. You need to throw an error at the end of the function.

However, since unhandled http errors (and other smaller errors that could be easily handled) will also throw the error at the end and will cause change detection to stop running. The trick is to only throw an error at the end when it's something that you cannot handle or that should cause change detection to stop running (like template errors)

like image 173
Fabrice TIERCELIN Avatar answered Sep 27 '22 17:09

Fabrice TIERCELIN