diff --git a/e2e/components/dialog/dialog.e2e.ts b/e2e/components/dialog/dialog.e2e.ts
index 907713ceeaae..7c160f62b561 100644
--- a/e2e/components/dialog/dialog.e2e.ts
+++ b/e2e/components/dialog/dialog.e2e.ts
@@ -11,6 +11,12 @@ describe('dialog', () => {
expectToExist('md-dialog-container');
});
+ it('should open a template dialog', () => {
+ expectToExist('.my-template-dialog', false);
+ element(by.id('template')).click();
+ expectToExist('.my-template-dialog');
+ });
+
it('should close by clicking on the backdrop', () => {
element(by.id('default')).click();
diff --git a/src/demo-app/dialog/dialog-demo.html b/src/demo-app/dialog/dialog-demo.html
index 53734bbbfdff..8b87d6e04d07 100644
--- a/src/demo-app/dialog/dialog-demo.html
+++ b/src/demo-app/dialog/dialog-demo.html
@@ -1,7 +1,14 @@
Dialog demo
-
-
+
+
+
@@ -51,3 +58,7 @@
Other options
Last close result: {{lastCloseResult}}
+
+
+ I'm a template dialog. I've been opened {{numTemplateOpens}} times!
+
diff --git a/src/demo-app/dialog/dialog-demo.ts b/src/demo-app/dialog/dialog-demo.ts
index 5e91c097f9aa..68a4c81fac82 100644
--- a/src/demo-app/dialog/dialog-demo.ts
+++ b/src/demo-app/dialog/dialog-demo.ts
@@ -1,4 +1,4 @@
-import {Component, Inject} from '@angular/core';
+import {Component, Inject, ViewChild, TemplateRef} from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser';
import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
@@ -23,6 +23,9 @@ export class DialogDemo {
right: ''
}
};
+ numTemplateOpens = 0;
+
+ @ViewChild(TemplateRef) template: TemplateRef;
constructor(public dialog: MdDialog, @Inject(DOCUMENT) doc: any) {
// Possible useful example for the open and closeAll events.
@@ -51,6 +54,11 @@ export class DialogDemo {
let dialogRef = this.dialog.open(ContentElementDialog, this.config);
dialogRef.componentInstance.actionsAlignment = this.actionsAlignment;
}
+
+ openTemplate() {
+ this.numTemplateOpens++;
+ this.dialog.open(this.template, this.config);
+ }
}
diff --git a/src/e2e-app/dialog/dialog-e2e.html b/src/e2e-app/dialog/dialog-e2e.html
index 827bfee99ca0..b66e8dfd8c51 100644
--- a/src/e2e-app/dialog/dialog-e2e.html
+++ b/src/e2e-app/dialog/dialog-e2e.html
@@ -1,2 +1,5 @@
+
+
+
my template dialog
diff --git a/src/e2e-app/dialog/dialog-e2e.ts b/src/e2e-app/dialog/dialog-e2e.ts
index 068406bbc5cb..09f833d96d0b 100644
--- a/src/e2e-app/dialog/dialog-e2e.ts
+++ b/src/e2e-app/dialog/dialog-e2e.ts
@@ -1,4 +1,4 @@
-import {Component} from '@angular/core';
+import {Component, ViewChild, TemplateRef} from '@angular/core';
import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
@Component({
@@ -9,6 +9,8 @@ import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
export class DialogE2E {
dialogRef: MdDialogRef;
+ @ViewChild(TemplateRef) templateRef: TemplateRef;
+
constructor (private _dialog: MdDialog) { }
private _openDialog(config?: MdDialogConfig) {
@@ -28,6 +30,10 @@ export class DialogE2E {
disableClose: true
});
}
+
+ openTemplate() {
+ this.dialogRef = this._dialog.open(this.templateRef);
+ }
}
@Component({
diff --git a/src/lib/dialog/dialog-container.ts b/src/lib/dialog/dialog-container.ts
index 415c6d31c1bb..c9aa19dcec04 100644
--- a/src/lib/dialog/dialog-container.ts
+++ b/src/lib/dialog/dialog-container.ts
@@ -52,7 +52,7 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
}
/**
- * Attach a portal as content to this dialog container.
+ * Attach a ComponentPortal as content to this dialog container.
* @param portal Portal to be attached as the dialog content.
*/
attachComponentPortal(portal: ComponentPortal): ComponentRef {
@@ -61,7 +61,29 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
}
let attachResult = this._portalHost.attachComponentPortal(portal);
+ this._trapFocus();
+ return attachResult;
+ }
+
+ /**
+ * Attach a TemplatePortal as content to this dialog container.
+ * @param portal Portal to be attached as the dialog content.
+ */
+ attachTemplatePortal(portal: TemplatePortal): Map {
+ if (this._portalHost.hasAttached()) {
+ throw new MdDialogContentAlreadyAttachedError();
+ }
+ let attachedResult = this._portalHost.attachTemplatePortal(portal);
+ this._trapFocus();
+ return attachedResult;
+ }
+
+ /**
+ * Moves the focus inside the focus trap.
+ * @private
+ */
+ private _trapFocus() {
// If were to attempt to focus immediately, then the content of the dialog would not yet be
// ready in instances where change detection has to run first. To deal with this, we simply
// wait for the microtask queue to be empty.
@@ -69,13 +91,6 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy {
this._elementFocusedBeforeDialogWasOpened = document.activeElement;
this._focusTrap.focusFirstTabbableElement();
});
-
- return attachResult;
- }
-
- /** @docs-private */
- attachTemplatePortal(portal: TemplatePortal): Map {
- throw Error('Not yet implemented');
}
/**
diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts
index 93e48cd6b2fc..95ea356b8d4c 100644
--- a/src/lib/dialog/dialog.ts
+++ b/src/lib/dialog/dialog.ts
@@ -1,17 +1,15 @@
-import {Injector, ComponentRef, Injectable, Optional, SkipSelf} from '@angular/core';
+import {Injector, ComponentRef, Injectable, Optional, SkipSelf, TemplateRef} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
-
import {Overlay, OverlayRef, ComponentType, OverlayState, ComponentPortal} from '../core';
import {extendObject} from '../core/util/object-extend';
-
import {DialogInjector} from './dialog-injector';
import {MdDialogConfig} from './dialog-config';
import {MdDialogRef} from './dialog-ref';
import {MdDialogContainer} from './dialog-container';
+import {TemplatePortal} from '../core/portal/portal';
-// TODO(jelbourn): add support for opening with a TemplateRef
// TODO(jelbourn): animations
@@ -53,16 +51,19 @@ export class MdDialog {
/**
* Opens a modal dialog containing the given component.
- * @param component Type of the component to load into the load.
+ * @param componentOrTemplateRef Type of the component to load into the dialog,
+ * or a TemplateRef to instantiate as the dialog content.
* @param config Extra configuration options.
* @returns Reference to the newly-opened dialog.
*/
- open(component: ComponentType, config?: MdDialogConfig): MdDialogRef {
+ open(componentOrTemplateRef: ComponentType | TemplateRef,
+ config?: MdDialogConfig): MdDialogRef {
config = _applyConfigDefaults(config);
let overlayRef = this._createOverlay(config);
let dialogContainer = this._attachDialogContainer(overlayRef, config);
- let dialogRef = this._attachDialogContent(component, dialogContainer, overlayRef, config);
+ let dialogRef =
+ this._attachDialogContent(componentOrTemplateRef, dialogContainer, overlayRef, config);
this._openDialogs.push(dialogRef);
dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef));
@@ -114,14 +115,15 @@ export class MdDialog {
/**
* Attaches the user-provided component to the already-created MdDialogContainer.
- * @param component The type of component being loaded into the dialog.
+ * @param componentOrTemplateRef The type of component being loaded into the dialog,
+ * or a TemplateRef to instantiate as the content.
* @param dialogContainer Reference to the wrapping MdDialogContainer.
* @param overlayRef Reference to the overlay in which the dialog resides.
* @param config The dialog configuration.
* @returns A promise resolving to the MdDialogRef that should be returned to the user.
*/
private _attachDialogContent(
- component: ComponentType,
+ componentOrTemplateRef: ComponentType | TemplateRef,
dialogContainer: MdDialogContainer,
overlayRef: OverlayRef,
config?: MdDialogConfig): MdDialogRef {
@@ -143,10 +145,13 @@ export class MdDialog {
let userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
let dialogInjector = new DialogInjector(dialogRef, userInjector || this._injector);
- let contentPortal = new ComponentPortal(component, null, dialogInjector);
-
- let contentRef = dialogContainer.attachComponentPortal(contentPortal);
- dialogRef.componentInstance = contentRef.instance;
+ if (componentOrTemplateRef instanceof TemplateRef) {
+ dialogContainer.attachTemplatePortal(new TemplatePortal(componentOrTemplateRef, null));
+ } else {
+ let contentRef = dialogContainer.attachComponentPortal(
+ new ComponentPortal(componentOrTemplateRef, null, dialogInjector));
+ dialogRef.componentInstance = contentRef.instance;
+ }
return dialogRef;
}