Ray
Ray

Reputation: 780

How to create a Confirmation Dialog box that can be called from any component in Angular 11?

I have created a modal as a separate component in my angular project as the following:

HTML:

<div mat-dialog-title>
  {{title}}
</div>
<div mat-dialog-content>
  <p>{{message}}</p>
</div>
<div mat-dialog-actions>
  <button mat-button color="primary" (click)="confirm()">{{btnOkText}}</button>
  <button mat-button (click)="decline()" cdkFocusInitial>{{btnCancelText}}</button>
</div>

TS:

export class ConfirmDialogComponent implements OnInit {

  title!: string;
  message!: string;
  btnOkText!: string;
  btnCancelText!: string;

  constructor(
    public dialogRef: MatDialogRef<ConfirmDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: ConfirmDialogModel) {
      // Update view with given values
      this.title = data.title;
      this.message = data.message;
      this.btnOkText = data.btnOkText;
      this.btnCancelText = data.btnCancelText;
    }

  ngOnInit(): void {
  }

  confirm() {
    // Close the dialog, return true
    this.dialogRef.close(true);
  }

  decline() {
    // Close the dialog, return false
    this.dialogRef.close(false);
  }

}

/**
 * Class to represent confirm dialog model.
 *
 * It has been kept here to keep it as part of shared component.
 */
 export class ConfirmDialogModel {

  constructor(
    public title: string,
    public message: string,
    public btnOkText: string,
    public btnCancelText: string) {
  }
}

I created a service that is root injected and put in a method that initialize and open the dialog box as the following:

confirmDialog(): void {
    const title = 'Confirmation';
    const message = 'Are you sure you want to do this?';
    const btnOkText = 'Ok';
    const btnCancelText = 'Cancel';

    const dialogData = new ConfirmDialogModel(title, message, btnOkText, btnCancelText);

    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      maxWidth: "400px",
      data: dialogData
    });

    dialogRef.afterClosed().subscribe(dialogResult => {
      dialogResult;
    });
}

If I console.log(dialogResult) I will get the right result (true/false)

All of that is good, however, I want to turn this dialogResult into an observable where any component calls my confirm service, gets to see the dialogResult then do an action based on it.

Example:

I have a home component and I injected my confirmService into it

constructor(private confirmService : ConfirmService) {}

then, in home.html, I created a button with (click) event like the following:

<button mat-raised-button color="primary" (click)="confirm()">Confirm</button>

The function confirm() is like the following:

confirm() {
    this.confirmService.confirmDialog();
}

I want to be able to subscribe to the confirmDialog() and get the result from it, how can I do that?

Upvotes: 0

Views: 8456

Answers (2)

Boris Jenicek
Boris Jenicek

Reputation: 203

Use this solution StackBlitzit is callable from any typescript file and without the need of an HTML selector. I suggest that you create a service and put this like confirm box as in this example so when you want to call it call just service method with text and color type argument that returns observable.

You can use this angular confirm box generator for testing https://costlydeveloper.github.io/ngx-awesome-popup/#/playground/confirm-box-generator


     openConfirmBox() {
        const newConfirmBox = new ConfirmBoxInitializer();

        newConfirmBox.setTitle('Title');
        newConfirmBox.setMessage('Your message!');

        // Choose layout color type
        newConfirmBox.setConfig({
        LayoutType: DialogLayoutDisplay.SUCCESS, // SUCCESS | INFO | NONE | DANGER | WARNING
        });

        // Simply open the ConfirmBox
        newConfirmBox.openConfirmBox$(); // subscribe to get button clicked response
    }

It is my personal work I code a full dialog system similar to mat dialog but a little different, with more functionality that supports multiple dialogs, added token functionality under the hood so the developer can call dialog above dialog in chronological order, button generator with observables, and so on. Also, it gives a complete solution for confirmation boxes, toast messages, and cookie banners with the same technology.

Later I put a little more effort and put it in the open-source library, wanted to share it with the community. Support it by giving a star to the Github repo. I hope you will find it useful.

https://github.com/costlydeveloper/ngx-awesome-popup

Upvotes: 1

Sameer
Sameer

Reputation: 5188

Wrap it in the observable like this

confirmDialog(): Observable<boolean> {
    return new Observable(observer => {
      ...
      dialogRef.afterClosed().subscribe(dialogResult => {
        observer.next(dialogResult);
        observer.complete(); //to avoid memory leaks
      });
    });
}

or simply return afterClosed since it is an observable, cast it to boolean.

confirmDialog(): Observable<boolean> {
    ...
    return dialogRef.afterClosed() as Observable<boolean>;
}

Then subscribe like this

confirm() {
    this.confirmService.confirmDialog().subscribe(isConfirmed => {
      console.log(isConfirmed);
    })
}

Upvotes: 4

Related Questions