Reputation: 11
I've gotten most of this example working thanks to other posts, but I'm still having one problem.
If I throw an error, the Error Dialog works as expected. The Error Dialog also works if I throw an HTTP error (including if I catch the error in pipe and return throwError(error)). However, if a typescript error as thrown if attempting to display an undefined object, the Error Dialog doesn't display data from the component, and the dialog doesn't close.
Here's the code I'm experimenting with.
import { BrowserModule } from '@angular/platform-browser';
import { Component, Inject, Injectable, OnInit, ErrorHandler, NgModule, NgZone } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { MatDialogModule } from '@angular/material/dialog';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@Component({
selector: 'app-root',
template: `
<div class="content">
<h1>{{title}}</h1>
<h3>{{something[0]['text']}}</h3>
<button (click)="forceFakeError()">Force Fake Error</button>
<br>
<button (click)="forceHttpError()">Force HTTP Error</button>
<br>
<button (click)="forceTypeError()">Force Type Error</button>
</div>
`,
styles: ['div.content {padding: 25px;}', 'button {margin: 10px}']
})
export class AppComponent {
title = 'dialog-issue';
something = [{ text: 'This is some test text' }];
data: any;
constructor(public dialog: MatDialog, private http: HttpClient) {}
forceFakeError() {
throw(new Error('Fake eror...'));
}
forceHttpError() {
this.http.get<any>('https://garbageinout.io').subscribe({
next: data => {
this.data = data;
},
error: error => {
console.error('There was an error!', error);
throw(error);
}
});
}
forceTypeError() {
this.something.length = 0;
}
}
@Injectable({
providedIn: 'root'
})
export class ErrorHandlerService implements ErrorHandler {
handling = false;
constructor(private dialog: MatDialog, private ngZone: NgZone) {}
handleError(error: any) {
if (this.handling) {
console.log('errorhandler already handling error message: ' + error.message);
return;
}
this.handling = true;
console.log('errorhandler error: ', error);
console.log('errorhandler error name: ' + error.constructor.name);
const errMsg = error.message ?? 'No message found!';
console.log('errorhandler error message: ' + error.message);
this.ngZone.run(() => {
this.displayErrorMessage('Application Error', errMsg)
.subscribe((resp) => {
console.log('Response is: ', resp);
this.handling = false;
});
});
}
displayErrorMessage(title: string, msg: string): Observable<string> {
const dialogRef = this.dialog.open(TestDialog,
{width: '400px', disableClose: true, data: { title: title, message: msg}
});
return dialogRef.afterClosed();
}
}
export interface ErrorData {
title: string;
message: string;
}
@Component({
selector: 'app-error',
template: `
<div>
<h1 mat-dialog-title>{{title}}</h1>
<div mat-dialog-content>
<p>Click OK to continue, or click on the "Click here"
link to restart the app.</p>
<p>Message: {{msg}}</p>
<p>{{dateTime()}}</p>
<p><a href="/index">Click here</a> to restart app</p>
</div>
<button mat-raised-button (click)="onClick()">OK</button>
</div>
`,
styles: ['button { margin: 5 }']
})
export class TestDialog implements OnInit {
title: string = 'Fake Title';
msg: string = 'Fake string';
constructor(public dialogRef: MatDialogRef<TestDialog>,
@Inject(MAT_DIALOG_DATA) public data: ErrorData) {
this.title = data.title;
this.msg = data.message ?? 'Message not provided...';
}
ngOnInit() {
console.log('error dialog, title: ', this.title, ', msg: ', this.msg);
}
dateTime(): string {
return new Date().toString();
}
onClick() {
console.log('entering error dialog onClick event');
this.dialogRef.close('OK!');
}
}
@NgModule({
declarations: [
AppComponent,
TestDialog
],
imports: [
BrowserModule,
BrowserAnimationsModule,
MatDialogModule
],
exports: [
HttpClientModule,
MatDialogModule
],
providers: [
{ provide: ErrorHandler, useClass: ErrorHandlerService }
],
bootstrap: [AppComponent]
})
export class AppModule { }
My environment is:
Angular CLI: 13.2.2
Node: 16.13.0
Package Manager: npm 8.4.1
OS: darwin arm64
Angular: 13.2.1
... animations, cdk, common, compiler, compiler-cli, core, forms
... material, platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1302.2
@angular-devkit/build-angular 13.2.2
@angular-devkit/core 13.2.2
@angular-devkit/schematics 13.2.2
@angular/cli 13.2.2
@schematics/angular 13.2.2
rxjs 7.5.2
typescript 4.5.5
and I'm using the command "ng serve --ssl --configuration production" for execution.
Thank you in advance for any insight on how to solve this problem.
Upvotes: 1
Views: 495
Reputation: 1051
That is because no Error
was raised. Your something
is an array and has a length property. Sure it should be readonly but javascript executes it no matter what - although it has no effect on the value of the length property.
You can test it directly in your browsers dev console. Just type and enter:
[].length = 0;
No error is raised.
I suppose your handler whould correctly handle something like this:
this.something.unknownProperty.anotherProperty = 0;
As unknownProperty
will return undefined, javascript can´t execute that statement. It can´t resolve anotherProperty
from undefined. That raises an error.
Upvotes: -1