How to communicate from mat dialog component to the component where mat dialog is implemented?

16,828

Solution 1

A use case scenario if you want to edit some data in a dialog then pass the edited data back to the component from the dialog. I used the example above but I consolidated the answer to make it easier to follow. Assuming the data is coming from a service this example shares data from a mat-dialog component to an app component in the same file.

// app.component.html  

<div *ngFor="let a of appData">
  <p>{{a.name}}</p>
<button> (click)="open(event, a)">edit</button> 
</div>
// app.component.ts    

import { Component, Inject, OnInit } from '@angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { DataService } from './data.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
 appData: Array <any>;

 constructor(private dataService: DataService, public dialog: MatDialog) {}

 ngOnInit() {

   this.dataService.getData()
    .subscribe(res => { 
      //console.log(res);
      this.appData = res;
   })
 }

public open(event, data) {
  this.dialog.open(EditDialog, {
    data: data,
}).afterClosed()
  .subscribe(item => {
    // Edited Data sent to App Component from Dialog 
    console.log(item);
  });
 }
}

@Component({
  selector: 'edit-dialog',
  template: `<span>Edit Data</span>
             <mat-dialog-content>
               <input matInput name="title" type="text" class="form-control" placeholder="Edit Name" [(ngModel)]="dataItem.name">
             </mat-dialog-content>
             <div>
               <span><button mat-raised-button (click)="updateData()">Update Recipe</button></span>
             </div>`,
 })

 export class EditDialog implements OnInit {

   dataItem: any;  

   constructor(public dialogRef: MatDialogRef <EditDialog> , @Inject(MAT_DIALOG_DATA) public data: any, private dataService: DataService) {
     this.dataItem = this.data;
   }

   public updateData() {
     this.dialogRef.close(this.dataItem);
   }

   ngOnInit() {
   }
}

Solution 2

You can actually achieve communication using subscription to @Output through MatDialogRef<EditDialog>. For some scenarios, you may need to get the data from a dialog before it is closed. Hence, we cannot make use of the this.DialogRef.afterClosed() function since we have to close the dialog first to get the data.

On your DialogComponent:

export class DialogComponent {

  @Output() submitClicked = new EventEmitter<any>();

  constructor(public dialogRef: MatDialogRef<DialogComponent>){}

  saveMessage() {
    const data = 'Your data';
    this.submitClicked.emit(data);
  }

  closeDialog() {
    this.dialogRef.close();
  }
}

On your AppComponent:

addItem() {
    this.DialogRef = this.dialog.open(DialogComponent);
    this.DialogRef.componentInstance.submitClicked.subscribe(result => {
        console.log('Got the data!', result);

    });
}

Better make sure to unsubscribe() all your Subscriptions. Something like this will do for a quick unsubscribe (if there's no validation of data involved):

const dialogSubmitSubscription = this.DialogRef.componentInstance.submitClicked
    .subscribe(result => {
      console.log('Got the data!', result);
      dialogSubmitSubscription.unsubscribe();
    });

Also, you can always close your dialog from the AppComponent with this.DialogRef.close() if you have to.

Solution 3

A. subscribe to the afterClosed Observable of this.DialogRef, you can add it after you call the this.DialogRef.open in app.component.ts Like this

  addItem() {
    this.DialogRef = this.dialog.open(DialogComponent);
    this.DialogRef.afterClosed()
    .subscribe(return => console.log(return));
  }

B. In dialog.component.ts import the MatDialog service, like this:

import { Component, Inject } from '@angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from'@angular/material';

C. Make sure that the dialogRef is passed to your dialog constructor like this

  constructor(public dialogRef: MatDialogRef<DialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: any) {}

C. In the saveMessage() method, call the close dialog method and pass the value that you need to return to app component.

  saveMessage() {
    this.dialogRef.close('hello data');
  } 

D. App component will receive the value because it subscribe to the afterClosed dialog observable

Also take a look at the full example form angular material docs

Cheers

Share:
16,828
karty
Author by

karty

Updated on June 19, 2022

Comments

  • karty
    karty almost 2 years

    I have a dialog component and app component where the material dialog is implemented. Here is the code of app component

    import { Component } from '@angular/core';
    import {VERSION, MatDialog, MatDialogRef} from '@angular/material';
    import { DialogComponent } from '../dialog.component';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {
      name = 'Angular 5';
      DialogRef: MatDialogRef<DialogComponent>;
      constructor(private dialog: MatDialog) {}
      ngOnInit() {
      }
      addItem() {
        this.DialogRef = this.dialog.open(DialogComponent);
      }
    
    receiveMessageFromDialogComponent() {
      // how to receive message from dialog component
    }
    closeDialog(): void {
      this.DialogRef.close();
    }
    }
    

    The dialog component is where the form is implemented, I need to take the form value and receive it in here. I tried using angular input and output to achieve this but dint work coz there is no child and parent communication. Here is the Dialog component

    import { Component } from '@angular/core';
    
    @Component({
      template: `
        <h1 mat-dialog-title>Add Item</h1>
        <mat-dialog-content>
        <mat-form-field  class="example-full-width">
            <input matInput placeholder="Item name here...">
        </mat-form-field>
        </mat-dialog-content>
        <mat-dialog-actions>
          <button mat-button (click)="saveMessage()">Add</button>
          <button mat-button (click)="closeDialog()">Cancel</button>
        </mat-dialog-actions>
      `
    })
    export class DialogComponent {
      saveMessage() {
        console.log('how to send data to the app component');
      }
      closeDialog() {
        console.log('how to close');
      }
    }
    

    Working Example on StackBlitz

  • java-addict301
    java-addict301 over 4 years
    This seems to be the correct answer per this thread github.com/angular/components/issues/3593
  • Admin
    Admin almost 4 years
    hi, can someone answer this question? thanks stackoverflow.com/questions/62807800/…
  • Dorin Baba
    Dorin Baba over 2 years
    Absolutely amazing and intuitive, thx bro