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

3

18

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

Homoeo answered 23/12, 2017 at 12:55 Comment(4)
Basically you want to pass your data from mat dialog form to you page where you came from right?Chlorosis
Yes. Thats what i asked in the question with code on stackblitzHomoeo
could be nice if you can edit my stackblitz.Homoeo
Possible duplicate of How to communicate from angular-material2 dialog to its parentWashhouse
U
12

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() {
   }
}
Undercarriage answered 23/3, 2018 at 5:26 Comment(0)
U
33

You can actually achieve communication using subscription to @Output through MatDialogRef<DialogComponent>. 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. Instead, we want to get the Component instance and access from there.

On your DialogComponent:

export class DialogComponent {
 
  @Output() submitClicked = new EventEmitter<any>();

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

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

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

On your AppComponent:

openDialog() {
    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);
      // do something here with the data
      dialogSubmitSubscription.unsubscribe();
    });

Also, you can always close your dialog from the AppComponent with this.dialogRef.close() if you have to. Or in the example above, you can also use the this.DialogRef.componentInstance.closeDialog().

Undistinguished answered 10/1, 2019 at 5:50 Comment(2)
This seems to be the correct answer per this thread github.com/angular/components/issues/3593Demoniac
Absolutely amazing and intuitive, thx broCivilized
U
12

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() {
   }
}
Undercarriage answered 23/3, 2018 at 5:26 Comment(0)
R
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

Rabassa answered 23/12, 2017 at 14:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.