Skip to content

Commit 5f682e2

Browse files
committed
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.
1 parent b49bfce commit 5f682e2

File tree

7 files changed

+87
-21
lines changed

7 files changed

+87
-21
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ <h2>Dialog position</h2>
2626

2727
<h2>Other options</h2>
2828

29-
<md-checkbox [(ngModel)]="config.disableClose">Disable close</md-checkbox>
29+
<p>
30+
<md-checkbox [(ngModel)]="config.disableClose">Disable close</md-checkbox>
31+
</p>
32+
33+
<p>
34+
<md-input [(ngModel)]="config.data.message" placeholder="Dialog message"></md-input>
35+
</p>
3036
</md-card-content>
3137
</md-card>
3238

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Component} from '@angular/core';
2-
import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
2+
import {MdDialog, MdDialogRef, MdDialogConfig, MdDialogData} from '@angular/material';
33

44
@Component({
55
moduleId: module.id,
@@ -19,6 +19,9 @@ export class DialogDemo {
1919
bottom: '',
2020
left: '',
2121
right: ''
22+
},
23+
data: {
24+
message: 'Jazzy jazz jazz'
2225
}
2326
};
2427

@@ -27,7 +30,7 @@ export class DialogDemo {
2730
openJazz() {
2831
this.dialogRef = this.dialog.open(JazzDialog, this.config);
2932

30-
this.dialogRef.afterClosed().subscribe(result => {
33+
this.dialogRef.afterClosed().subscribe((result: string) => {
3134
this.lastCloseResult = result;
3235
this.dialogRef = null;
3336
});
@@ -44,13 +47,13 @@ export class DialogDemo {
4447
template: `
4548
<p>It's Jazz!</p>
4649
<p><label>How much? <input #howMuch></label></p>
47-
<p> {{ jazzMessage }} </p>
50+
<p> {{ data.message }} </p>
4851
<button type="button" (click)="dialogRef.close(howMuch.value)">Close dialog</button>`
4952
})
5053
export class JazzDialog {
51-
jazzMessage = 'Jazzy jazz jazz';
52-
53-
constructor(public dialogRef: MdDialogRef<JazzDialog>) { }
54+
constructor(
55+
public dialogRef: MdDialogRef<JazzDialog>,
56+
public data: MdDialogData) { }
5457
}
5558

5659

src/lib/dialog/README.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ MdDialog is a service, which opens dialogs components in the view.
1313

1414
| Key | Description |
1515
| --- | ------------ |
16-
| `role: DialogRole = 'dialog'` | The ARIA role of the dialog element. Possible values are `dialog` and `alertdialog`. Optional. |
17-
| `disableClose: boolean = false` | Whether to prevent the user from closing a dialog by clicking on the backdrop or pressing escape. Optional. |
18-
| `width: string = ''` | Width of the dialog. Takes any valid CSS value. Optional. |
19-
| `height: string = ''` | Height of the dialog. Takes any valid CSS value. Optional. |
20-
| `position: { top?: string, bottom?: string, left?: string, right?: string }` | Position of the dialog that overrides the default centering in it's axis. Optional. |
21-
| `viewContainerRef: ViewContainerRef` | The view container ref to attach the dialog to. Optional. |
16+
| `role?: DialogRole = 'dialog'` | The ARIA role of the dialog element. Possible values are `dialog` and `alertdialog`. |
17+
| `disableClose?: boolean = false` | Whether to prevent the user from closing a dialog by clicking on the backdrop or pressing escape. |
18+
| `data?: { [key: string]: any }` | Data that will be injected into the dialog as `MdDialogData`. |
19+
| `width?: string = ''` | Width of the dialog. Takes any valid CSS value. |
20+
| `height?: string = ''` | Height of the dialog. Takes any valid CSS value. |
21+
| `position?: { top?: string, bottom?: string, left?: string, right?: string }` | Position of the dialog that overrides the default centering in it's axis. |
22+
| `viewContainerRef?: ViewContainerRef` | The view container ref to attach the dialog to. |
2223

2324
## MdDialogRef
2425

@@ -57,7 +58,10 @@ export class PizzaComponent {
5758

5859
openDialog() {
5960
this.dialogRef = this.dialog.open(PizzaDialog, {
60-
disableClose: false
61+
disableClose: false,
62+
data: {
63+
pizzaType: 'pepperoni'
64+
}
6165
});
6266

6367
this.dialogRef.afterClosed().subscribe(result => {
@@ -70,7 +74,7 @@ export class PizzaComponent {
7074
@Component({
7175
selector: 'pizza-dialog',
7276
template: `
73-
<h1 md-dialog-title>Would you like to order pizza?</h1>
77+
<h1 md-dialog-title>Would you like to order a {{ data.pizzaType }} pizza?</h1>
7478
7579
<md-dialog-actions>
7680
<button (click)="dialogRef.close('yes')">Yes</button>
@@ -79,7 +83,9 @@ export class PizzaComponent {
7983
`
8084
})
8185
export class PizzaDialog {
82-
constructor(public dialogRef: MdDialogRef<PizzaDialog>) { }
86+
constructor(
87+
public dialogRef: MdDialogRef<PizzaDialog>,
88+
public data: MdDialogData) { }
8389
}
8490
```
8591

src/lib/dialog/dialog-config.ts

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

14+
/** Data to be injected into a dialog. */
15+
export class MdDialogData {
16+
[key: string]: any;
17+
}
1418

1519
/**
1620
* Configuration for opening a modal dialog with the MdDialog service.
@@ -33,5 +37,8 @@ export class MdDialogConfig {
3337
/** Position overrides. */
3438
position?: DialogPosition;
3539

40+
/** Data being injected into the child component. */
41+
data?: MdDialogData;
42+
3643
// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
3744
}

src/lib/dialog/dialog-injector.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import {Injector} from '@angular/core';
22
import {MdDialogRef} from './dialog-ref';
3+
import {MdDialogData} from './dialog-config';
34

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 _dialogRef: MdDialogRef<any>,
10+
private _data: MdDialogData,
11+
private _parentInjector: Injector) { }
812

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

18+
if (token === MdDialogData && 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: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {MdDialog} from './dialog';
1414
import {OverlayContainer} from '../core';
1515
import {MdDialogRef} from './dialog-ref';
1616
import {MdDialogContainer} from './dialog-container';
17+
import {MdDialogData} from './dialog-config';
1718

1819

1920
describe('MdDialog', () => {
@@ -227,6 +228,28 @@ describe('MdDialog', () => {
227228
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
228229
});
229230

231+
describe('passing in data', () => {
232+
it('should be able to pass in data', () => {
233+
let config = {
234+
data: {
235+
stringParam: 'hello',
236+
dateParam: new Date()
237+
}
238+
};
239+
240+
let instance = dialog.open(DialogWithInjectedData, config).componentInstance;
241+
242+
expect(instance.data['stringParam']).toBe(config.data.stringParam);
243+
expect(instance.data['dateParam']).toBe(config.data.dateParam);
244+
});
245+
246+
it('should throw if injected data is expected but none is passed', () => {
247+
expect(() => {
248+
dialog.open(DialogWithInjectedData);
249+
}).toThrow();
250+
});
251+
});
252+
230253
describe('disableClose option', () => {
231254
it('should prevent closing via clicks on the backdrop', () => {
232255
dialog.open(PizzaMsg, {
@@ -454,19 +477,31 @@ class ComponentThatProvidesMdDialog {
454477
constructor(public dialog: MdDialog) {}
455478
}
456479

480+
/** Simple component for testing ComponentPortal. */
481+
@Component({template: ''})
482+
class DialogWithInjectedData {
483+
constructor(public data: MdDialogData) { }
484+
}
485+
457486
// Create a real (non-test) NgModule as a workaround for
458487
// https://github.com/angular/angular/issues/10760
459488
const TEST_DIRECTIVES = [
460489
ComponentWithChildViewContainer,
461490
PizzaMsg,
462491
DirectiveWithViewContainer,
463-
ContentElementDialog
492+
ContentElementDialog,
493+
DialogWithInjectedData
464494
];
465495

466496
@NgModule({
467497
imports: [MdDialogModule],
468498
exports: TEST_DIRECTIVES,
469499
declarations: TEST_DIRECTIVES,
470-
entryComponents: [ComponentWithChildViewContainer, PizzaMsg, ContentElementDialog],
500+
entryComponents: [
501+
ComponentWithChildViewContainer,
502+
PizzaMsg,
503+
ContentElementDialog,
504+
DialogWithInjectedData
505+
],
471506
})
472507
class DialogTestModule { }

src/lib/dialog/dialog.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ export class MdDialog {
105105
// Create a reference to the dialog we're creating in order to give the user a handle
106106
// to modify and close it.
107107
let dialogRef = <MdDialogRef<T>> new MdDialogRef(overlayRef);
108+
let config: MdDialogConfig = dialogContainer.dialogConfig;
108109

109-
if (!dialogContainer.dialogConfig.disableClose) {
110+
if (!config.disableClose) {
110111
// When the dialog backdrop is clicked, we want to close it.
111112
overlayRef.backdropClick().first().subscribe(() => dialogRef.close());
112113
}
@@ -117,7 +118,7 @@ export class MdDialog {
117118
// We create an injector specifically for the component we're instantiating so that it can
118119
// inject the MdDialogRef. This allows a component loaded inside of a dialog to close itself
119120
// and, optionally, to return a value.
120-
let dialogInjector = new DialogInjector(dialogRef, this._injector);
121+
let dialogInjector = new DialogInjector(dialogRef, config.data, this._injector);
121122

122123
let contentPortal = new ComponentPortal(component, null, dialogInjector);
123124

0 commit comments

Comments
 (0)