Trouble with Angular Material Dialog Staying Open

Within my Angular application, I have implemented a Material dialog to present error messages to users. To handle errors effectively, I have crafted an error service with methods dedicated to managing both server-side (HTTP) errors and client-side errors.

import { Injectable } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class ErrorService {
  getClientMessage(error: Error): string {
    if (!navigator.onLine) {
      return 'No Internet Connection';
    }
    return error.message ? error.message : error.toString();
  }

  // Other methods omitted for brevity
}

In my setup, I utilize an HTTP interceptor to intercept HTTP errors.

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  // Implementation details omitted
}

Upon encountering errors, I have a global error handler in place that extends Angular's default ErrorHandler.

import { ErrorHandler, Injectable } from '@angular/core';
// Other imports and service initialization omitted
@Injectable({
  providedIn: 'root'
})
export class GlobalErrorHandler implements ErrorHandler {
  // Handler method logic
}

Despite the setup, I have encountered an issue regarding the functionality of the error dialog box. While client-side errors are handled seamlessly, HTTP errors exhibit unexpected behavior with the dialog box not functioning as intended. Further analysis is required to pinpoint the root cause of this discrepancy.

Problem Statement: The primary concern revolves around the error dialog box behavior. Despite displaying the dialog box and error component appropriately, encountering HTTP errors leads to inconsistencies in dialog functionality. Here is an overview of my error dialog component...

import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
// Component details omitted for brevity

To validate the error handling mechanism, I incorporated test buttons in the view...


<button (click)="throwError()">Error</button>
<button (click)="throwHttpError()">HTTP</button>
// Component methods for generating errors

Although client-side errors trigger the expected responses, HTTP errors lead to unexpected behavior within the error dialog component. Possible attributing factors such as zone-related issues or subscription inconsistencies warrant further investigation to rectify the issue.

Answer №1

I managed to find a solution for the issue at hand, although the exact cause eludes me. Nevertheless, I was able to tweak my code to achieve the desired outcome. Below is the revised version of my code...

HttpErrorInterceptor

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpErrorResponse,
  HttpHeaders
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { ErrorDialogComponent } from './error-dialog.component';
import { PathLocationStrategy } from '@angular/common';
import { ErrorService } from './error.service';
import { LoggerService } from './logger.service';

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  constructor(
    public dialog: MatDialog,
    private errorService: ErrorService,
    private logger: LoggerService
  ) {}

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      retry(1),
      catchError((error: HttpErrorResponse) => {
        // Message variable to hold error message
        let errorMessage = '';
        // Variable to hold stacktrace
        let stacktrace;
        // Variable to hold url location of error
        const url =
          location instanceof PathLocationStrategy ? location.path() : '';
        // Header options for http post
        const options = {
          headers: new HttpHeaders({
            'Content-Type': 'application/x-www-form-urlencoded'
          })
        };
        // server-side error
        errorMessage = this.errorService.getServerMessage(error);
        stacktrace = this.errorService.getServerStack(error);
        // log errors
        this.logger.logError(errorMessage, stacktrace);
        if (typeof errorMessage !== 'undefined') {
          this.openDialog(errorMessage);
        } else {
          this.openDialog('undefined');
        }
        return throwError(errorMessage);
      })
    );
  }
  openDialog(data): void {
    const dialogRef = this.dialog.open(ErrorDialogComponent, {
      width: '60%',
      data: data
    });

    dialogRef.afterClosed().subscribe(result => {
      // Redirect back to home (dashboard)?
      console.log('in afterClosed http: ' + result);
    });
  }
}

GlobalErrorHandler

import { ErrorHandler, Injectable, Injector } from '@angular/core';
import {
  HttpErrorResponse,
  HttpHeaders,
  HttpClient
} from '@angular/common/http';
import { PathLocationStrategy } from '@angular/common';
import { throwError, Observable } from 'rxjs';
import * as StackTrace from 'stacktrace-js';
import { LoggerService } from '../core/logger.service';
import { ErrorService } from '../core/error.service';
import { MatDialog } from '@angular/material';
import { ErrorDialogComponent } from './error-dialog.component';

@Injectable({
  providedIn: 'root'
})
export class GlobalErrorHandler implements ErrorHandler {
  // Error handling is important and needs to be loaded first.
  // Because of this we should manually inject the services with Injector.
  constructor(
    private injector: Injector,
    public dialog: MatDialog,
    private http: HttpClient
  ) {}
  // Function to handle errors
  handleError(error: Error) {
    const errorService = this.injector.get(ErrorService);
    const logger = this.injector.get(LoggerService);
    // Header options for http post
    const options = {
      headers: new HttpHeaders({
        'Content-Type': 'application/x-www-form-urlencoded'
      })
    };
    // Message variable to hold error message
    let errorMessage;
    // Variable to hold stacktrace
    let stacktrace;
    // Variable to hold url location of error
    const url = location instanceof PathLocationStrategy ? location.path() : '';
    if (error instanceof Error) {
      // Client Error
      errorMessage = errorService.getClientMessage(error);
      stacktrace = errorService.getClientStack(error);
      this.openDialog(errorMessage);
    }
    // log errors
    logger.logError(errorMessage, stacktrace);
    return throwError(error);
  }
  openDialog(data): void {
    const dialogRef = this.dialog.open(ErrorDialogComponent, {
      width: '60%',
      data: data
    });

    dialogRef.afterClosed().subscribe(result => {
      // Redirect back to home (dashboard)?
      console.log('in afterClosed error: ' + result);
    });
  }
}

Everything else stayed unchanged.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 4 Bootstrap 4 Collapsible Navigation Bar

Struggling for a while now trying to achieve the exact functionality I desire. Within my Angular Universal App, there is a vertical navigation bar at the top that I want to make responsive for mobile devices. I am utilizing Bootstrap 4 Alpha 6 and ngx-boot ...

Angular 4+ directive allowing interaction with the NgModel of a component

I'm looking to update styles based on the state of NgModel.control. To keep it DRY, I was thinking that a directive for reading the NgModel component state could be the solution. Is this actually feasible? I haven't been able to find any guidanc ...

Tips for inserting values into a string array using jQuery or Angular 7

I have a series of checkboxes with values obtained from a loop. Instead of pushing these values into an array, I need to join them together as "parent1", "parent2", "parent3" and display the result in the console. Below is the code snippet for reference: ...

Azure deployment of a proprietary npm package

As a developer with git integration for my Angular web site, I have successfully checked code into Git and deployed it to Azure. Everything was running smoothly until I encountered an issue when trying to pull a private npm package. It dawned on me that I ...

Tips on automatically changing the background image every few seconds

As a newcomer to Angular and programming in general, I am facing an issue with changing the background image of my Page using the setInterval method. The intended behavior is for it to change every second, but for some reason, it changes much faster than t ...

Switching buttons with AngularJS

I am currently working on a Github search app using the Github API in Angular. My goal is to make it so that when the user clicks the "Add to Favorite" button, the button disappears and the "Remove Favorite" button is displayed instead. I attempted to achi ...

"Encountering a Server Error when attempting to refresh routing children

My project is hosted on a subDirectory server with Apache. The base index for my project can either be <base href="./"> or <base href="/myFolder/">. The issue arises when I am on a child route page, for example: www.mysite ...

Creating templates for both classes and individual objects is an essential part of object-oriented programming

I am working on a simple game project using TypeScript. My goal is to utilize interfaces to implement them in classes and pass them as arguments for creating new instances of a class. interface ObjectConstructor { element: HTMLElement; x_pos: numbe ...

What is the best way to broaden the capabilities of function objects through the use of

Below is a code snippet that raises the question of how one should define certain types. In this scenario, it is required that Bar extends Foo and the return type of FooBar should be 'a'. interface Foo { (...args: any):any b: string } i ...

Challenges with image cropping in Angular causing performance problems

Utilizing this specific component for image cropping within an ionic/angular8 project has been causing severe performance issues, leading to unresponsiveness on mobile devices. Interestingly, the desktop version does not encounter any problems and the crop ...

Create an Angular material table with expandable rows that become sticky when scrolled past, then automatically unstick once they are no longer in view

Currently, I am working with Angular Material Table v11.1.0 which includes a main row with expandable rows. I want the main row to become sticky once an expandable row is opened and remain sticky while scrolling through the table. My goal is for the main ...

Tips on extracting status response codes from the backend and incorporating them into the frontend

I have a Node.js backend and an Angular frontend, and I need to send status response codes from the backend to display an error message "Email already exists" on the frontend. // Frontend add.user.component.ts if (this.AddUserForm.valid) { this. ...

Encountering difficulty in establishing a global variable within the subscribe function

I am looking to store the service response in a variable for use in my view. The TypeScript file I am working with is shown below: The MenuService is a custom service that includes a function called getMenus() to fetch all menus from the database. import ...

Add a css class to a <div> that is created by an <ng-template> inside the <ngx-datatable-column> element

I am struggling to implement the display: flex style on the parent <div> containing my <span> However, since the <span> is dynamically generated by the ng-template of the ngx-datatable-column, I'm finding it challenging to apply thi ...

Methods for bypassing a constructor in programming

I am working on a code where I need to define a class called programmer that inherits from the employee class. The employee class constructor should have 4 parameters, and the programmer class constructor needs to have 5 parameters - 4 from the employee c ...

"Receiving an error message stating 'Was expecting 1 parameter, received 2' while trying to pass a useState function in TypeScript

I am encountering an issue with a component where I pass a useState setter to a utility function: export interface IData { editable: string[]; favourited: string[]; } const [data, setData] = useState<IData | undefined>(undefined) useEffect(() = ...

Deciphering the .vimrc setup for tooltips and symbols in TypeScript

Currently, I have integrated the Tsuquyomi plugin for my typescript development in Vim. The documentation mentions tooltips for symbols under the cursor, which are working fine. The issue arises as I am using terminal-based Vim, and even if I were using a ...

Transform Angular into a library

I've been exploring different options but still haven't nailed down the best approach. I've developed an Angular library with custom components, which I'm converting into Web Components to be used in non-Angular applications. But to mak ...

Tips on leveraging separate files for classes in TypeScript

I'm currently working on developing a TypeScript application where each class is saved in its own .ts file. I prefer to use VS Code for this project. So far, my compile task seems to be functioning correctly (transpiling .ts files into .js files). How ...

Using Keyof on a type combined with Record<string, unknown> results in missing properties and can cause errors when paired with Omit<T, K>

I encountered a situation that has left me unsure whether it is an actual issue or simply a misunderstanding on my part. Upon reviewing this code snippet: type Props = { foo: string bar: string } & Record<string, unknown> // Using Record< ...