Skip to content

Commit 29cbe61

Browse files
crisbetotinayuangao
authored andcommitted
feat(dialog): add a config option for passing in data (#2266)
* feat(dialog): add a config option for passing in data Adds the ability to pass in data to a dialog via the `data` property. While this was previously possible through the `dialogRef.componentInstance.someUserSuppliedProperty`, it wasn't the most intuitive. The new approach looks like this: ``` dialog.open(SomeDialog, { data: { hello: 'world' } }); class SometDialog { constructor(data: MdDialogData) { console.log(data['hello']); } } ``` Fixes #2181. * Switch to using an OpaqueToken. * chore: fix aot errors
1 parent e5ca565 commit 29cbe61

File tree

7 files changed

+81
-16
lines changed

7 files changed

+81
-16
lines changed

src/demo-app/dialog/dialog-demo.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,15 @@ <h2>Other options</h2>
4646
</md-select>
4747
</p>
4848

49-
<md-checkbox [(ngModel)]="config.disableClose">Disable close</md-checkbox>
49+
<p>
50+
<md-input-container>
51+
<input mdInput [(ngModel)]="config.data.message" placeholder="Dialog message">
52+
</md-input-container>
53+
</p>
54+
55+
<p>
56+
<md-checkbox [(ngModel)]="config.disableClose">Disable close</md-checkbox>
57+
</p>
5058
</md-card-content>
5159
</md-card>
5260

src/demo-app/dialog/dialog-demo.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {Component, Inject} from '@angular/core';
22
import {DOCUMENT} from '@angular/platform-browser';
3-
import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
3+
import {MdDialog, MdDialogRef, MdDialogConfig, MD_DIALOG_DATA} from '@angular/material';
4+
45

56
@Component({
67
moduleId: module.id,
@@ -21,6 +22,9 @@ export class DialogDemo {
2122
bottom: '',
2223
left: '',
2324
right: ''
25+
},
26+
data: {
27+
message: 'Jazzy jazz jazz'
2428
}
2529
};
2630

@@ -41,7 +45,7 @@ export class DialogDemo {
4145
openJazz() {
4246
this.dialogRef = this.dialog.open(JazzDialog, this.config);
4347

44-
this.dialogRef.afterClosed().subscribe(result => {
48+
this.dialogRef.afterClosed().subscribe((result: string) => {
4549
this.lastCloseResult = result;
4650
this.dialogRef = null;
4751
});
@@ -59,13 +63,13 @@ export class DialogDemo {
5963
template: `
6064
<p>It's Jazz!</p>
6165
<p><label>How much? <input #howMuch></label></p>
62-
<p> {{ jazzMessage }} </p>
66+
<p> {{ data.message }} </p>
6367
<button type="button" (click)="dialogRef.close(howMuch.value)">Close dialog</button>`
6468
})
6569
export class JazzDialog {
66-
jazzMessage = 'Jazzy jazz jazz';
67-
68-
constructor(public dialogRef: MdDialogRef<JazzDialog>) { }
70+
constructor(
71+
public dialogRef: MdDialogRef<JazzDialog>,
72+
@Inject(MD_DIALOG_DATA) public data: any) { }
6973
}
7074

7175

@@ -104,7 +108,7 @@ export class JazzDialog {
104108
color="primary"
105109
href="https://en.wikipedia.org/wiki/Neptune"
106110
target="_blank">Read more on Wikipedia</a>
107-
111+
108112
<button
109113
md-button
110114
color="secondary"

src/lib/dialog/dialog-config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export interface DialogPosition {
1111
right?: string;
1212
};
1313

14-
1514
/**
1615
* Configuration for opening a modal dialog with the MdDialog service.
1716
*/
@@ -33,5 +32,8 @@ export class MdDialogConfig {
3332
/** Position overrides. */
3433
position?: DialogPosition;
3534

35+
/** Data being injected into the child component. */
36+
data?: any;
37+
3638
// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
3739
}

src/lib/dialog/dialog-injector.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1-
import {Injector} from '@angular/core';
1+
import {Injector, OpaqueToken} from '@angular/core';
22
import {MdDialogRef} from './dialog-ref';
33

4+
export const MD_DIALOG_DATA = new OpaqueToken('MdDialogData');
45

56
/** Custom injector type specifically for instantiating components with a dialog. */
67
export class DialogInjector implements Injector {
7-
constructor(private _dialogRef: MdDialogRef<any>, private _parentInjector: Injector) { }
8+
constructor(
9+
private _parentInjector: Injector,
10+
private _dialogRef: MdDialogRef<any>,
11+
private _data: any) { }
812

913
get(token: any, notFoundValue?: any): any {
1014
if (token === MdDialogRef) {
1115
return this._dialogRef;
1216
}
1317

18+
if (token === MD_DIALOG_DATA && this._data) {
19+
return this._data;
20+
}
21+
1422
return this._parentInjector.get(token, notFoundValue);
1523
}
1624
}

src/lib/dialog/dialog.spec.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,21 @@ import {
77
TestBed,
88
tick,
99
} from '@angular/core/testing';
10+
import {NgModule,
11+
Component,
12+
Directive,
13+
ViewChild,
14+
ViewContainerRef,
15+
Injector,
16+
Inject,
17+
} from '@angular/core';
1018
import {By} from '@angular/platform-browser';
11-
import {NgModule, Component, Directive, ViewChild, ViewContainerRef, Injector} from '@angular/core';
1219
import {MdDialogModule} from './index';
1320
import {MdDialog} from './dialog';
1421
import {OverlayContainer} from '../core';
1522
import {MdDialogRef} from './dialog-ref';
1623
import {MdDialogContainer} from './dialog-container';
24+
import {MD_DIALOG_DATA} from './dialog-injector';
1725

1826

1927
describe('MdDialog', () => {
@@ -271,6 +279,28 @@ describe('MdDialog', () => {
271279
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
272280
});
273281

282+
describe('passing in data', () => {
283+
it('should be able to pass in data', () => {
284+
let config = {
285+
data: {
286+
stringParam: 'hello',
287+
dateParam: new Date()
288+
}
289+
};
290+
291+
let instance = dialog.open(DialogWithInjectedData, config).componentInstance;
292+
293+
expect(instance.data.stringParam).toBe(config.data.stringParam);
294+
expect(instance.data.dateParam).toBe(config.data.dateParam);
295+
});
296+
297+
it('should throw if injected data is expected but none is passed', () => {
298+
expect(() => {
299+
dialog.open(DialogWithInjectedData);
300+
}).toThrow();
301+
});
302+
});
303+
274304
describe('disableClose option', () => {
275305
it('should prevent closing via clicks on the backdrop', () => {
276306
dialog.open(PizzaMsg, {
@@ -505,19 +535,31 @@ class ComponentThatProvidesMdDialog {
505535
constructor(public dialog: MdDialog) {}
506536
}
507537

538+
/** Simple component for testing ComponentPortal. */
539+
@Component({template: ''})
540+
class DialogWithInjectedData {
541+
constructor(@Inject(MD_DIALOG_DATA) public data: any) { }
542+
}
543+
508544
// Create a real (non-test) NgModule as a workaround for
509545
// https://github.com/angular/angular/issues/10760
510546
const TEST_DIRECTIVES = [
511547
ComponentWithChildViewContainer,
512548
PizzaMsg,
513549
DirectiveWithViewContainer,
514-
ContentElementDialog
550+
ContentElementDialog,
551+
DialogWithInjectedData
515552
];
516553

517554
@NgModule({
518555
imports: [MdDialogModule],
519556
exports: TEST_DIRECTIVES,
520557
declarations: TEST_DIRECTIVES,
521-
entryComponents: [ComponentWithChildViewContainer, PizzaMsg, ContentElementDialog],
558+
entryComponents: [
559+
ComponentWithChildViewContainer,
560+
PizzaMsg,
561+
ContentElementDialog,
562+
DialogWithInjectedData
563+
],
522564
})
523565
class DialogTestModule { }

src/lib/dialog/dialog.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export class MdDialog {
129129
// to modify and close it.
130130
let dialogRef = <MdDialogRef<T>> new MdDialogRef(overlayRef);
131131

132-
if (!dialogContainer.dialogConfig.disableClose) {
132+
if (!config.disableClose) {
133133
// When the dialog backdrop is clicked, we want to close it.
134134
overlayRef.backdropClick().first().subscribe(() => dialogRef.close());
135135
}
@@ -141,7 +141,7 @@ export class MdDialog {
141141
// inject the MdDialogRef. This allows a component loaded inside of a dialog to close itself
142142
// and, optionally, to return a value.
143143
let userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
144-
let dialogInjector = new DialogInjector(dialogRef, userInjector || this._injector);
144+
let dialogInjector = new DialogInjector(userInjector || this._injector, dialogRef, config.data);
145145

146146
let contentPortal = new ComponentPortal(component, null, dialogInjector);
147147

src/lib/dialog/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,4 @@ export * from './dialog-container';
5757
export * from './dialog-content-directives';
5858
export * from './dialog-config';
5959
export * from './dialog-ref';
60+
export {MD_DIALOG_DATA} from './dialog-injector';

0 commit comments

Comments
 (0)