13

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

kian
  • 1,449
  • 2
  • 13
  • 21
karty
  • 187
  • 1
  • 1
  • 10
  • Basically you want to pass your data from mat dialog form to you page where you came from right? – Selaka Nanayakkara Dec 23 '17 at 12:58
  • Yes. Thats what i asked in the question with code on stackblitz – karty Dec 23 '17 at 13:01
  • could be nice if you can edit my stackblitz. – karty Dec 23 '17 at 13:53
  • Possible duplicate of [How to communicate from angular-material2 dialog to its parent](https://stackoverflow.com/questions/42717508/how-to-communicate-from-angular-material2-dialog-to-its-parent) – Jun Mar 02 '19 at 22:28

3 Answers3

28

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().

Alex Pappas
  • 2,377
  • 3
  • 24
  • 48
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() {
   }
}
Ian Poston Framer
  • 938
  • 12
  • 16
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

Daniel C.
  • 5,418
  • 3
  • 23
  • 26
  • hi, can someone answer this question? thanks https://stackoverflow.com/questions/62807800/angular-material-popup-windows-allow-windows-to-go-between-front-and-back –  Jul 09 '20 at 05:09