feature request
I'd like to use something like this (just like mat-menu):
<button (click)="myDialog.open()">Open it</button>
<mat-dialog (result)="onResult($event)" #myDialog>
<h1 mat-dialog-title>Dialog Title</h1>
<mat-dialog-content>
Content
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button mat-button [mat-dialog-close]="true">Confirm</button>
</mat-dialog-actions>
</mat-dialog>
Doesn't exist as fat as I have seen in the docs and source code.
I've created a small component which demonstrates what I'm looking for:
https://stackblitz.com/edit/angular-material2-issue-tp5aej?file=app%2Fapp.component.html
(I didn't get mat-dialog-close working with the projection, though I chose to just add a method to my dialog component)
There are many use cases where I just want a very simple dialog, and don't want to write 30 lines of code.
Angular 6 beta
Material 6 beta
This can be done using <ng-template>:
app.component.html:
<button mat-button (click)="openDialogWithRef(myDialog)">Open dialog with template ref</button>
<!-- or... -->
<button mat-button (click)="openDialogWithoutRef()">Open dialog without template ref</button>
<ng-template #myDialog>
<h2 matDialogTitle>Dialog!</h2>
<mat-dialog-content>
<p>Dialog content goes here</p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button matDialogClose color="primary">DISMISS</button>
</mat-dialog-actions>
</ng-template>
<ng-template #secondDialog>
<h2 matDialogTitle>Such dialog very wow!</h2>
<mat-dialog-content>
<p><em>*insert meme here*</em></p>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button matDialogClose color="primary">Shutdown dialog</button>
</mat-dialog-actions>
</ng-template>
app.component.ts:
import { ViewChild, TemplateRef } from '@angular/core';
import { MatDialog } from '@angular/material';
// ...
export class AppComponent {
@ViewChild('secondDialog') secondDialog: TemplateRef<any>;
constructor(private dialog: MatDialog) { }
openDialogWithRef(templateRef: TemplateRef<any>) {
this.dialog.open(templateRef);
}
openDialogWithoutRef() {
this.dialog.open(this.secondDialog);
}
}
Demo
See the code in the snippet below for more info:
https://github.com/angular/components/blob/c28549d088c4462bf64078db5442a123542bf1be/src/lib/dialog/dialog.ts#L105-L113
Thank you.
But your solution doesn't support the Dialog results. Using dialogRef.afterClosed().subscribe(...) will make the code even larger, and I guess it's not that easy to say #myDialog1 should call onFirstResult($event) and #myDialog2 should call onSecondResult($event).
I would like to add that if you need MatDialogRef instance in your dialog component in the <ng-template> pattern @Chan4077 suggested above, it's as easy as:
<ng-template #myDialog let-dialogRef="dialogRef">
<my-dialog [dialogRef]="dialogRef"></my-dialog>
</ng-template>
I like this usage and I think it would be nice if the usage is clearly documented.
This has been solved in #9379 even before this issue came up.
A naive wrapper component could look like this
import { ChangeDetectionStrategy, Component, ContentChild, EventEmitter, Output, TemplateRef } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material';
@Component({
selector: 'app-dialog',
templateUrl: './dialog.component.html',
styleUrls: ['./dialog.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DialogComponent {
@ContentChild(TemplateRef) template: TemplateRef<{}>;
@Output() result = new EventEmitter();
dRef: MatDialogRef<any>;
constructor (private dialog: MatDialog) {}
open () {
this.dRef = this.dialog.open(this.template);
this.dRef.afterClosed().subscribe(val => this.result.emit(val));
}
}
Use it like this:
<button (click)="d.open()">click me</button>
<app-dialog #d (result)="onResult($event)">
<ng-template>
<button [mat-dialog-close]="someProperty">leave me alone!</button>
</ng-template>
</app-dialog>
caveat:
both DialogComponent and MatDialogClose have to be available in the template. A missing directive fails silently, so make sure to reexport MatDialogClose or import MatDialogModule
@benneq Thanks for your solution for a temporary MatDialog implementation!
@j2L4e It looks like that [mat-dialog-close] inside a dialog TemplateRef fails even after exporting MatDialogClose and/or importing MatDialogModule in the closest parent module:
jit_nodeValue_3(...).dialogRef.close is not a function
at Object.eval [as handleEvent] (TestComponent.html:17)
at handleEvent (core.js:23009)
at callWithDebugContext (core.js:24079)
at Object.debugHandleEvent [as handleEvent] (core.js:23806)
at dispatchEvent (core.js:20458)
at core.js:20905
at HTMLButtonElement.<anonymous> (platform-browser.js:993)
IMO, this is a documentation issue. https://material.angular.io/components/dialog/overview needs an example with TemplateRef using implicit context. This is difficult to figure out if you're not comfortable looking at material2's source code.
The $implicit context is bound to MatDialogConfig.data, which I don't think most people know about. So in this code example, foo, which is arbitrary, is bound to $implicit, which is from MatDialogConfig.data, see _material2/src/lib/dialog/dialog.ts_ _attachDialogContent()
<ng-template #myTemp let-foo>
<h2 matDialogTitle>My Title</h2>
<mat-dialog-content>
<p>{{ foo.myProperty }}</p>
</mat-dialog-content>
</ng-template>
Then, you need to bind TemplateRef in your component, or just pass it by reference when calling a function from the template.
<button mat-stroked-button
(click)="openDialog(myTemp, myData)">
Open Dialog
</button>
Component .ts
openDialog(templateRef: TemplateRef<MyData>, myData: MyData) {
this.dialog.open(templateRef, { data: myData });
}
@arlowhite, didn't you get the error:
ERROR Error: No component factory found for undefined. Did you add it to @NgModule.entryComponents?
?
@tonyuifalean Could you show us your code?
If you're facing an unrelated issue, I suggest that you should either try to ask on StackOverflow or open a new issue on this repository.
@EdricChan03: I am using Angular 8, and I am just testing @arlowhite's example.
In my template I have:

In the component I have a method, called in ngOnInit:
@ViewChild('myTemp', { static: false })
public myTemp: TemplateRef
public openMyDialog() {
this.dialog.open(this.myTemp);
}
And in the module I import: MatDialogModule
Could you try moving the public myTemp line to the same line as the ViewChild(...) line? And is there any reason why you're marking _all_ of the methods and properties as public?
@arlowhite Actually, if you look closely in the documentation for TemplateRef, passing in the data interface as the T type parameter will not make any difference than passing in any as TemplateRef is defined to have a C type parameter which is the template's class.
So here's the modified version of your component code:
openDialog(templateRef: TemplateRef<any>, myData: MyData) {
this.dialog.open(templateRef, { data: myData });
}
Oops, never mind. I did not read the bottom part that mentioned what the C type parameter is for:
The data-binding context of the embedded view, as declared in the聽
<ng-template>聽usage.
Could you try moving the
public myTempline to the same line as theViewChild(...)line? And is there any reason why you're marking _all_ of the methods and properties aspublic?
Just for testing purposes. In the end I'll try to use a component directly, but thanks for you support!
Most helpful comment
I would like to add that if you need
MatDialogRefinstance in your dialog component in the<ng-template>pattern @Chan4077 suggested above, it's as easy as:I like this usage and I think it would be nice if the usage is clearly documented.