Reputation: 237
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');
}
}
Upvotes: 18
Views: 29222
Reputation: 2658
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 Subscription
s. 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()
.
Upvotes: 33
Reputation: 958
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() {
}
}
Upvotes: 12
Reputation: 5758
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
Upvotes: 3