diff --git a/src/demo-app/demo-app-module.ts b/src/demo-app/demo-app-module.ts index 47b54dbb1036..8454f65ddd5f 100644 --- a/src/demo-app/demo-app-module.ts +++ b/src/demo-app/demo-app-module.ts @@ -8,7 +8,14 @@ import {MaterialModule, OverlayContainer, FullscreenOverlayContainer} from '@angular/material'; import {DEMO_APP_ROUTES} from './demo-app/routes'; import {ProgressBarDemo} from './progress-bar/progress-bar-demo'; -import {JazzDialog, ContentElementDialog, DialogDemo, IFrameDialog} from './dialog/dialog-demo'; +import { + JazzDialog, + JazzDialogTemplateRef, + ContentElementDialog, + ContentElementTemplateRefDialog, + DialogDemo, + IFrameDialog +} from './dialog/dialog-demo'; import {RippleDemo} from './ripple/ripple-demo'; import {IconDemo} from './icon/icon-demo'; import {GesturesDemo} from './gestures/gestures-demo'; @@ -64,7 +71,9 @@ import {InputContainerDemo} from './input/input-container-demo'; IconDemo, InputContainerDemo, JazzDialog, + JazzDialogTemplateRef, ContentElementDialog, + ContentElementTemplateRefDialog, IFrameDialog, ListDemo, LiveAnnouncerDemo, @@ -100,7 +109,9 @@ import {InputContainerDemo} from './input/input-container-demo'; entryComponents: [ DemoApp, JazzDialog, + JazzDialogTemplateRef, ContentElementDialog, + ContentElementTemplateRefDialog, IFrameDialog, RotiniPanel, ScienceJoke, diff --git a/src/demo-app/dialog/dialog-demo.html b/src/demo-app/dialog/dialog-demo.html index 53734bbbfdff..bca0a178f16a 100644 --- a/src/demo-app/dialog/dialog-demo.html +++ b/src/demo-app/dialog/dialog-demo.html @@ -1,53 +1,107 @@

Dialog demo

- - - - - -

Dialog dimensions

- -

- - - - - - -

- -

Dialog position

- -

- - - - - - -

- -

- - - - - - -

- -

Other options

- -

- - Start - End - Center - -

- - Disable close -
-
- -

Last close result: {{lastCloseResult}}

+
+ +

Using MdDialog service

+ +
+ + +
+ +
+ + +
+ +

Last close result: {{lastCloseResult}}

+ + + + + +
+ +
+ +

Using md-dialog element

+ +
+ +
+ + + + + + + + +
+ +
+ +

Dialog settings

+ + + +

Dialog dimensions

+ +

+ + + + + + +

+ +

Dialog position

+ +

+ + + + + + +

+ +

+ + + + + + +

+ +

Other options

+ +

+ + Start + End + Center + +

+ + Disable close +
+
+ +
diff --git a/src/demo-app/dialog/dialog-demo.scss b/src/demo-app/dialog/dialog-demo.scss index 6f7f4cac254a..0928ec509352 100644 --- a/src/demo-app/dialog/dialog-demo.scss +++ b/src/demo-app/dialog/dialog-demo.scss @@ -6,3 +6,15 @@ max-width: 350px; margin: 20px 0; } + +.demo-button-group { + margin-bottom: 20px; +} + +.demo-dialog-section { + margin-bottom: 40px; + + h2 { + font-size: 18px; + } +} diff --git a/src/demo-app/dialog/dialog-demo.ts b/src/demo-app/dialog/dialog-demo.ts index 5e91c097f9aa..cefa43b9c8d8 100644 --- a/src/demo-app/dialog/dialog-demo.ts +++ b/src/demo-app/dialog/dialog-demo.ts @@ -1,4 +1,12 @@ -import {Component, Inject} from '@angular/core'; +import { + Component, + Inject, + Input, + Output, + ViewChild, + TemplateRef, + EventEmitter +} from '@angular/core'; import {DOCUMENT} from '@angular/platform-browser'; import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material'; @@ -9,9 +17,18 @@ import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material'; styleUrls: ['dialog-demo.css'], }) export class DialogDemo { + @ViewChild('jazzDialogRef') + jazzDialogRef: TemplateRef; + + @ViewChild('contentElementRef') + contentElementRef: TemplateRef; + dialogRef: MdDialogRef; + dialogTemplateRef: MdDialogRef; + dialogContentTemplateRef: MdDialogRef; lastCloseResult: string; actionsAlignment: string; + mdDialogState: boolean = false; config: MdDialogConfig = { disableClose: false, width: '', @@ -41,16 +58,47 @@ export class DialogDemo { openJazz() { this.dialogRef = this.dialog.open(JazzDialog, this.config); - this.dialogRef.afterClosed().subscribe(result => { + this.dialogRef.afterClosed().first().subscribe(result => { this.lastCloseResult = result; this.dialogRef = null; }); } + openJazzUsingTemplateRef() { + this.dialogTemplateRef = this.dialog.openFromTemplateRef(this.jazzDialogRef, this.config); + + this.dialogTemplateRef.afterClosed().first().subscribe(() => { + this.dialogTemplateRef = null; + }); + } + + closeJazzUsingTemplateRef(result: string) { + this.lastCloseResult = result; + + this.dialogTemplateRef.close(); + } + openContentElement() { let dialogRef = this.dialog.open(ContentElementDialog, this.config); dialogRef.componentInstance.actionsAlignment = this.actionsAlignment; } + + openContentElementUsingTemplateRef() { + this.dialogContentTemplateRef = this.dialog.openFromTemplateRef( + this.contentElementRef, + this.config + ); + } + + closeContentElementUsingTemplateRef() { + if (this.dialogContentTemplateRef) { + this.dialogContentTemplateRef.close(); + } + } + + changeMdDialogState(to: boolean) { + this.mdDialogState = to; + } } @@ -69,6 +117,24 @@ export class JazzDialog { } +@Component({ + selector: 'demo-jazz-dialog-template-ref', + template: ` +

It's Jazz!

+

+

{{ jazzMessage }}

+ ` +}) +export class JazzDialogTemplateRef { + jazzMessage = 'Jazzy jazz jazz'; + + @Output() + close = new EventEmitter(false); + + constructor() { } +} + + @Component({ selector: 'demo-content-element-dialog', styles: [ @@ -98,13 +164,12 @@ export class JazzDialog { md-raised-button color="primary" md-dialog-close>Close - Read more on Wikipedia - + + Read more on Wikipedia + + + + ` +}) +export class ContentElementTemplateRefDialog { + @Input() + actionsAlignment: string; + + @Output() + close = new EventEmitter(); + + constructor(public dialog: MdDialog) { } + + showInStackedDialog() { + this.dialog.open(IFrameDialog); + } +} + @Component({ selector: 'demo-iframe-dialog', styles: [ diff --git a/src/lib/dialog/dialog-container.ts b/src/lib/dialog/dialog-container.ts index 6004809e8e05..7a496e38613e 100644 --- a/src/lib/dialog/dialog-container.ts +++ b/src/lib/dialog/dialog-container.ts @@ -5,6 +5,8 @@ import { ViewEncapsulation, NgZone, OnDestroy, + ViewContainerRef, + TemplateRef, } from '@angular/core'; import {BasePortalHost, ComponentPortal, PortalHostDirective, TemplatePortal} from '../core'; import {MdDialogConfig} from './dialog-config'; @@ -46,7 +48,7 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { /** Reference to the open dialog. */ dialogRef: MdDialogRef; - constructor(private _ngZone: NgZone) { + constructor(private _viewContainerRef: ViewContainerRef, private _ngZone: NgZone) { super(); } @@ -61,20 +63,27 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { let attachResult = this._portalHost.attachComponentPortal(portal); - // 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. - this._ngZone.onMicrotaskEmpty.first().subscribe(() => { - this._elementFocusedBeforeDialogWasOpened = document.activeElement; - this._focusTrap.focusFirstTabbableElement(); - }); + this._focusFirstTabbableElement(); return attachResult; } - /** @docs-private */ attachTemplatePortal(portal: TemplatePortal): Map { - throw Error('Not yet implemented'); + if (this._portalHost.hasAttached()) { + throw new MdDialogContentAlreadyAttachedError(); + } + + let attachResult = this._portalHost.attachTemplatePortal(portal); + + this._focusFirstTabbableElement(); + + return attachResult; + } + + attachTemplateRef(templateRef: TemplateRef) { + const portal = new TemplatePortal(templateRef, this._viewContainerRef); + + this.attachTemplatePortal(portal); } /** @@ -85,6 +94,8 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { if (!this.dialogConfig.disableClose) { this.dialogRef.close(); } + + this.dialogRef.escapePressed.next(); } ngOnDestroy() { @@ -95,4 +106,14 @@ export class MdDialogContainer extends BasePortalHost implements OnDestroy { (this._elementFocusedBeforeDialogWasOpened as HTMLElement).focus(); }); } + + private _focusFirstTabbableElement() { + // 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. + this._ngZone.onMicrotaskEmpty.first().subscribe(() => { + this._elementFocusedBeforeDialogWasOpened = document.activeElement; + this._focusTrap.focusFirstTabbableElement(); + }); + } } diff --git a/src/lib/dialog/dialog-element.html b/src/lib/dialog/dialog-element.html new file mode 100644 index 000000000000..71be36331855 --- /dev/null +++ b/src/lib/dialog/dialog-element.html @@ -0,0 +1,3 @@ + diff --git a/src/lib/dialog/dialog-element.ts b/src/lib/dialog/dialog-element.ts new file mode 100644 index 000000000000..316acb7a8c92 --- /dev/null +++ b/src/lib/dialog/dialog-element.ts @@ -0,0 +1,89 @@ +import { + Component, + TemplateRef, + Input, + ViewChild, + Output, + EventEmitter, + ChangeDetectionStrategy, + ViewEncapsulation, + NgZone +} from '@angular/core'; +import {MdDialog} from './dialog'; +import {MdDialogConfig} from './dialog-config'; +import {MdDialogRef} from './dialog-ref'; +import {Subscription} from 'rxjs/Subscription'; + +@Component({ + moduleId: module.id, + selector: 'md-dialog', + templateUrl: 'dialog-element.html', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class MdDialogElement { + dialog: MdDialogRef; + + @Input() + set config(v: MdDialogConfig) { + if (v) { + this._config = Object.assign(this._config, v); + } + } + get config() { + return this._config; + } + + /** emits event that close attemps happened along with a cause */ + @Output() + close = new EventEmitter<'escape' | 'backdrop'>(false); + + @ViewChild('mdDialogContentTemplateRef') + mdDialogContentTemplateRef: TemplateRef; + + @Input() + set open(state: boolean) { + if (state) { + // needed to prevent `Expression has changed after it was checked` + this._ngZone.onMicrotaskEmpty.first().subscribe(() => { + this.dialog = this._dialog.openFromTemplateRef( + this.mdDialogContentTemplateRef, + this.config + ); + + this._backdropClickSubscription = this.dialog + .backdropClicked + .subscribe(() => this.close.emit('backdrop')); + + this._escapePressSubscription = this.dialog + .escapePressed + .subscribe(() => this.close.emit('escape')); + }); + + } else if (this.dialog) { + if (this.dialog) { + this.dialog.close(); + + // remove backdrop/escape subscription only if dialog was actually closed + this._backdropClickSubscription.unsubscribe(); + this._escapePressSubscription.unsubscribe(); + } + } + } + + private _config: MdDialogConfig; + private _backdropClickSubscription: Subscription; + private _escapePressSubscription: Subscription; + + constructor(private _dialog: MdDialog, private _ngZone: NgZone) { + let config = new MdDialogConfig(); + + // disable close by default, to make it + // truly stateless it's default behaviour of + // https://developer.mozilla.org/en/docs/Web/HTML/Element/dialog + // as well + config.disableClose = true; + + this._config = config; + } +} diff --git a/src/lib/dialog/dialog-ref.ts b/src/lib/dialog/dialog-ref.ts index bd9a45df84ac..29cb4f904b64 100644 --- a/src/lib/dialog/dialog-ref.ts +++ b/src/lib/dialog/dialog-ref.ts @@ -14,10 +14,18 @@ export class MdDialogRef { /** The instance of component opened into the dialog. */ componentInstance: T; + /** Expose overlay backdrop click event */ + backdropClicked: Observable; + + /** Subject for notifying the user that esc key way pressed */ + escapePressed = new Subject(); + /** Subject for notifying the user that the dialog has finished closing. */ private _afterClosed: Subject = new Subject(); - constructor(private _overlayRef: OverlayRef) { } + constructor(private _overlayRef: OverlayRef) { + this.backdropClicked = this._overlayRef.backdropClick(); + } /** * Close the dialog. diff --git a/src/lib/dialog/dialog.spec.ts b/src/lib/dialog/dialog.spec.ts index e4196924deaa..6b6a5ca07467 100644 --- a/src/lib/dialog/dialog.spec.ts +++ b/src/lib/dialog/dialog.spec.ts @@ -8,14 +8,22 @@ import { tick, } from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {NgModule, Component, Directive, ViewChild, ViewContainerRef, Injector} from '@angular/core'; +import { + NgModule, + Component, + Directive, + ViewChild, + ViewContainerRef, + Injector, + TemplateRef +} from '@angular/core'; import {MdDialogModule} from './index'; import {MdDialog} from './dialog'; +import {MdDialogConfig} from './dialog-config'; import {OverlayContainer} from '../core'; import {MdDialogRef} from './dialog-ref'; import {MdDialogContainer} from './dialog-container'; - describe('MdDialog', () => { let dialog: MdDialog; let overlayContainerElement: HTMLElement; @@ -64,6 +72,98 @@ describe('MdDialog', () => { expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); }); + it('should open a dialog with a templateRef', () => { + const catDialogContainer = TestBed.createComponent(CatDialogContainer); + + catDialogContainer.detectChanges(); + + dialog.openFromTemplateRef(catDialogContainer.componentInstance.catRef); + + viewContainerFixture.detectChanges(); + + expect(overlayContainerElement.textContent).toContain('Cat'); + + viewContainerFixture.detectChanges(); + let dialogContainerElement = overlayContainerElement.querySelector('md-dialog-container'); + expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); + }); + + it('should open dialog using md-dialog component', () => { + const dialogComponentContainer = TestBed.createComponent(DialogComponentContainer); + + dialogComponentContainer.detectChanges(); + + expect(overlayContainerElement.textContent).toBe(''); + + dialogComponentContainer.componentInstance.changeState(true); + + dialogComponentContainer.detectChanges(); + viewContainerFixture.detectChanges(); + + expect(overlayContainerElement.textContent).toContain('Hello'); + + viewContainerFixture.detectChanges(); + let dialogContainerElement = overlayContainerElement.querySelector('md-dialog-container'); + expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); + + }); + + it('should close md-dialog component by changing "open" input to false', () => { + const dialogComponentContainer = TestBed.createComponent(DialogComponentContainer); + + dialogComponentContainer.componentInstance.changeState(true); + + dialogComponentContainer.detectChanges(); + + expect(overlayContainerElement.textContent).toContain('Hello'); + + dialogComponentContainer.componentInstance.changeState(false); + + dialogComponentContainer.detectChanges(); + viewContainerFixture.detectChanges(); + + expect(overlayContainerElement.querySelector('md-dialog-container')).toBeNull(); + + }); + + it('should not close dialog by default when using md-dialog', () => { + const dialogComponentContainer = TestBed.createComponent(DialogComponentContainer); + + dialogComponentContainer.componentInstance.changeState(true); + + dialogComponentContainer.detectChanges(); + viewContainerFixture.detectChanges(); + + expect(overlayContainerElement.textContent).toContain('Hello'); + + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + backdrop.click(); + + expect(overlayContainerElement.querySelector('md-dialog-container')).toBeTruthy(); + + }); + + it('should allow md-dialog settings to be changed with "config" input', () => { + const dialogComponentContainer = TestBed.createComponent(DialogComponentContainer); + + dialogComponentContainer.componentInstance.config = { + disableClose: false + }; + + dialogComponentContainer.componentInstance.changeState(true); + + dialogComponentContainer.detectChanges(); + viewContainerFixture.detectChanges(); + + expect(overlayContainerElement.textContent).toContain('Hello'); + + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + backdrop.click(); + + expect(overlayContainerElement.querySelector('md-dialog-container')).toBeFalsy(); + + }); + it('should use injector from viewContainerRef for DialogInjector', () => { let dialogRef = dialog.open(PizzaMsg, { viewContainerRef: testViewContainerRef @@ -120,7 +220,6 @@ describe('MdDialog', () => { expect(overlayContainerElement.querySelector('md-dialog-container')).toBeNull(); }); - it('should close a dialog via the escape key', () => { dialog.open(PizzaMsg, { viewContainerRef: testViewContainerRef @@ -137,6 +236,28 @@ describe('MdDialog', () => { expect(overlayContainerElement.querySelector('md-dialog-container')).toBeNull(); }); + it('should notify the user that escape key was pressed', () => { + let dialogRef = dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef + }); + + viewContainerFixture.detectChanges(); + + let dialogContainer: MdDialogContainer = + viewContainerFixture.debugElement.query(By.directive(MdDialogContainer)).componentInstance; + + let pressed = false; + + dialogRef.escapePressed.subscribe(() => { + pressed = true; + }); + + // Fake the user pressing the escape key by calling the handler directly. + dialogContainer.handleEscapeKey(); + + expect(pressed).toBe(true); + }); + it('should close when clicking on the overlay backdrop', () => { dialog.open(PizzaMsg, { viewContainerRef: testViewContainerRef @@ -150,6 +271,25 @@ describe('MdDialog', () => { expect(overlayContainerElement.querySelector('md-dialog-container')).toBeFalsy(); }); + it('should notify the user that overlay backdrop was clicked', () => { + let dialogRef = dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef + }); + + viewContainerFixture.detectChanges(); + + let backdrop = overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement; + + let clicked = false; + + dialogRef.backdropClicked.subscribe(() => { + clicked = true; + }); + + backdrop.click(); + expect(clicked).toBe(true); + }); + it('should notify the observers if a dialog has been opened', () => { let ref: MdDialogRef; dialog.afterOpen.subscribe(r => { @@ -483,6 +623,35 @@ class PizzaMsg { public dialogInjector: Injector) {} } +/** Components for testing dialog using TemplateRef. */ +@Component({selector: 'cat-dialog', template: '

Cat

'}) +class CatDialog {} + +@Component({template: ''}) +class CatDialogContainer { + @ViewChild('catRef') catRef: TemplateRef; +} + +/** Components for testing md-dialog component. */ +@Component({ + template: ` + + Hello + + ` +}) +class DialogComponentContainer { + state: boolean = false; + config: MdDialogConfig; + + changeState(to: boolean) { + this.state = to; + } +} + @Component({ template: `

This is the title

@@ -510,14 +679,24 @@ class ComponentThatProvidesMdDialog { const TEST_DIRECTIVES = [ ComponentWithChildViewContainer, PizzaMsg, + CatDialog, + CatDialogContainer, + DialogComponentContainer, DirectiveWithViewContainer, - ContentElementDialog + ContentElementDialog, ]; @NgModule({ imports: [MdDialogModule], exports: TEST_DIRECTIVES, declarations: TEST_DIRECTIVES, - entryComponents: [ComponentWithChildViewContainer, PizzaMsg, ContentElementDialog], + entryComponents: [ + ComponentWithChildViewContainer, + DialogComponentContainer, + PizzaMsg, + CatDialog, + CatDialogContainer, + ContentElementDialog, + ], }) class DialogTestModule { } diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index 93e48cd6b2fc..e20e4dcc9d06 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -1,4 +1,4 @@ -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'; @@ -10,12 +10,8 @@ import {MdDialogConfig} from './dialog-config'; import {MdDialogRef} from './dialog-ref'; import {MdDialogContainer} from './dialog-container'; - -// TODO(jelbourn): add support for opening with a TemplateRef // TODO(jelbourn): animations - - /** * Service to open Material Design modal dialogs. */ @@ -51,6 +47,34 @@ export class MdDialog { private _injector: Injector, @Optional() @SkipSelf() private _parentDialog: MdDialog) { } + /** + * Opens a modal dialog containing the given TemplateRef. + * @param TemplateRef to load into the dialog + * @param config Extra configuration options. + * @returns Reference to the newly-opened dialog. + */ + openFromTemplateRef(templateRef: TemplateRef, config?: MdDialogConfig): MdDialogRef { + config = _applyConfigDefaults(config); + + let overlayRef = this._createOverlay(config); + + let dialogContainer = this._attachDialogContainer(overlayRef, config); + let dialogRef = this._attachDialogContent( + dialogContainer, + overlayRef, + undefined, + templateRef, + config + ); + + this._openDialogs.push(dialogRef); + dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef)); + this._afterOpen.next(dialogRef); + + return dialogRef; + + } + /** * Opens a modal dialog containing the given component. * @param component Type of the component to load into the load. @@ -62,7 +86,13 @@ export class MdDialog { let overlayRef = this._createOverlay(config); let dialogContainer = this._attachDialogContainer(overlayRef, config); - let dialogRef = this._attachDialogContent(component, dialogContainer, overlayRef, config); + let dialogRef = this._attachDialogContent( + dialogContainer, + overlayRef, + component, + undefined, + config + ); this._openDialogs.push(dialogRef); dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef)); @@ -121,9 +151,10 @@ export class MdDialog { * @returns A promise resolving to the MdDialogRef that should be returned to the user. */ private _attachDialogContent( - component: ComponentType, dialogContainer: MdDialogContainer, overlayRef: OverlayRef, + component: ComponentType, + templateRef: TemplateRef, config?: MdDialogConfig): MdDialogRef { // Create a reference to the dialog we're creating in order to give the user a handle // to modify and close it. @@ -143,10 +174,16 @@ 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); + if (component) { + let contentPortal = new ComponentPortal(component, null, dialogInjector); - let contentRef = dialogContainer.attachComponentPortal(contentPortal); - dialogRef.componentInstance = contentRef.instance; + let contentRef = dialogContainer.attachComponentPortal(contentPortal); + dialogRef.componentInstance = contentRef.instance; + } + + if (templateRef) { + dialogContainer.attachTemplateRef(templateRef); + } return dialogRef; } diff --git a/src/lib/dialog/index.ts b/src/lib/dialog/index.ts index e14bc904b78b..b499fbef6c25 100644 --- a/src/lib/dialog/index.ts +++ b/src/lib/dialog/index.ts @@ -6,6 +6,7 @@ import { CompatibilityModule, } from '../core'; import {MdDialog} from './dialog'; +import {MdDialogElement} from './dialog-element'; import {MdDialogContainer} from './dialog-container'; import { MdDialogClose, @@ -14,7 +15,6 @@ import { MdDialogActions } from './dialog-content-directives'; - @NgModule({ imports: [ OverlayModule, @@ -24,6 +24,7 @@ import { ], exports: [ MdDialogContainer, + MdDialogElement, MdDialogClose, MdDialogTitle, MdDialogContent, @@ -32,6 +33,7 @@ import { ], declarations: [ MdDialogContainer, + MdDialogElement, MdDialogClose, MdDialogTitle, MdDialogActions, @@ -53,6 +55,7 @@ export class MdDialogModule { } export * from './dialog'; +export * from './dialog-element'; export * from './dialog-container'; export * from './dialog-content-directives'; export * from './dialog-config';