mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
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
This commit is contained in:
committed by
tinayuangao
parent
e5ca565a5f
commit
29cbe61296
@@ -46,7 +46,15 @@
|
||||
</md-select>
|
||||
</p>
|
||||
|
||||
<md-checkbox [(ngModel)]="config.disableClose">Disable close</md-checkbox>
|
||||
<p>
|
||||
<md-input-container>
|
||||
<input mdInput [(ngModel)]="config.data.message" placeholder="Dialog message">
|
||||
</md-input-container>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<md-checkbox [(ngModel)]="config.disableClose">Disable close</md-checkbox>
|
||||
</p>
|
||||
</md-card-content>
|
||||
</md-card>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {DOCUMENT} from '@angular/platform-browser';
|
||||
import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
|
||||
import {MdDialog, MdDialogRef, MdDialogConfig, MD_DIALOG_DATA} from '@angular/material';
|
||||
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
@@ -21,6 +22,9 @@ export class DialogDemo {
|
||||
bottom: '',
|
||||
left: '',
|
||||
right: ''
|
||||
},
|
||||
data: {
|
||||
message: 'Jazzy jazz jazz'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,7 +45,7 @@ export class DialogDemo {
|
||||
openJazz() {
|
||||
this.dialogRef = this.dialog.open(JazzDialog, this.config);
|
||||
|
||||
this.dialogRef.afterClosed().subscribe(result => {
|
||||
this.dialogRef.afterClosed().subscribe((result: string) => {
|
||||
this.lastCloseResult = result;
|
||||
this.dialogRef = null;
|
||||
});
|
||||
@@ -59,13 +63,13 @@ export class DialogDemo {
|
||||
template: `
|
||||
<p>It's Jazz!</p>
|
||||
<p><label>How much? <input #howMuch></label></p>
|
||||
<p> {{ jazzMessage }} </p>
|
||||
<p> {{ data.message }} </p>
|
||||
<button type="button" (click)="dialogRef.close(howMuch.value)">Close dialog</button>`
|
||||
})
|
||||
export class JazzDialog {
|
||||
jazzMessage = 'Jazzy jazz jazz';
|
||||
|
||||
constructor(public dialogRef: MdDialogRef<JazzDialog>) { }
|
||||
constructor(
|
||||
public dialogRef: MdDialogRef<JazzDialog>,
|
||||
@Inject(MD_DIALOG_DATA) public data: any) { }
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +108,7 @@ export class JazzDialog {
|
||||
color="primary"
|
||||
href="https://en.wikipedia.org/wiki/Neptune"
|
||||
target="_blank">Read more on Wikipedia</a>
|
||||
|
||||
|
||||
<button
|
||||
md-button
|
||||
color="secondary"
|
||||
|
||||
@@ -11,7 +11,6 @@ export interface DialogPosition {
|
||||
right?: string;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Configuration for opening a modal dialog with the MdDialog service.
|
||||
*/
|
||||
@@ -33,5 +32,8 @@ export class MdDialogConfig {
|
||||
/** Position overrides. */
|
||||
position?: DialogPosition;
|
||||
|
||||
/** Data being injected into the child component. */
|
||||
data?: any;
|
||||
|
||||
// TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling.
|
||||
}
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import {Injector} from '@angular/core';
|
||||
import {Injector, OpaqueToken} from '@angular/core';
|
||||
import {MdDialogRef} from './dialog-ref';
|
||||
|
||||
export const MD_DIALOG_DATA = new OpaqueToken('MdDialogData');
|
||||
|
||||
/** Custom injector type specifically for instantiating components with a dialog. */
|
||||
export class DialogInjector implements Injector {
|
||||
constructor(private _dialogRef: MdDialogRef<any>, private _parentInjector: Injector) { }
|
||||
constructor(
|
||||
private _parentInjector: Injector,
|
||||
private _dialogRef: MdDialogRef<any>,
|
||||
private _data: any) { }
|
||||
|
||||
get(token: any, notFoundValue?: any): any {
|
||||
if (token === MdDialogRef) {
|
||||
return this._dialogRef;
|
||||
}
|
||||
|
||||
if (token === MD_DIALOG_DATA && this._data) {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
return this._parentInjector.get(token, notFoundValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,21 @@ import {
|
||||
TestBed,
|
||||
tick,
|
||||
} from '@angular/core/testing';
|
||||
import {NgModule,
|
||||
Component,
|
||||
Directive,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
Injector,
|
||||
Inject,
|
||||
} from '@angular/core';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {NgModule, Component, Directive, ViewChild, ViewContainerRef, Injector} from '@angular/core';
|
||||
import {MdDialogModule} from './index';
|
||||
import {MdDialog} from './dialog';
|
||||
import {OverlayContainer} from '../core';
|
||||
import {MdDialogRef} from './dialog-ref';
|
||||
import {MdDialogContainer} from './dialog-container';
|
||||
import {MD_DIALOG_DATA} from './dialog-injector';
|
||||
|
||||
|
||||
describe('MdDialog', () => {
|
||||
@@ -271,6 +279,28 @@ describe('MdDialog', () => {
|
||||
expect(overlayContainerElement.querySelectorAll('md-dialog-container').length).toBe(0);
|
||||
});
|
||||
|
||||
describe('passing in data', () => {
|
||||
it('should be able to pass in data', () => {
|
||||
let config = {
|
||||
data: {
|
||||
stringParam: 'hello',
|
||||
dateParam: new Date()
|
||||
}
|
||||
};
|
||||
|
||||
let instance = dialog.open(DialogWithInjectedData, config).componentInstance;
|
||||
|
||||
expect(instance.data.stringParam).toBe(config.data.stringParam);
|
||||
expect(instance.data.dateParam).toBe(config.data.dateParam);
|
||||
});
|
||||
|
||||
it('should throw if injected data is expected but none is passed', () => {
|
||||
expect(() => {
|
||||
dialog.open(DialogWithInjectedData);
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('disableClose option', () => {
|
||||
it('should prevent closing via clicks on the backdrop', () => {
|
||||
dialog.open(PizzaMsg, {
|
||||
@@ -505,19 +535,31 @@ class ComponentThatProvidesMdDialog {
|
||||
constructor(public dialog: MdDialog) {}
|
||||
}
|
||||
|
||||
/** Simple component for testing ComponentPortal. */
|
||||
@Component({template: ''})
|
||||
class DialogWithInjectedData {
|
||||
constructor(@Inject(MD_DIALOG_DATA) public data: any) { }
|
||||
}
|
||||
|
||||
// Create a real (non-test) NgModule as a workaround for
|
||||
// https://github.com/angular/angular/issues/10760
|
||||
const TEST_DIRECTIVES = [
|
||||
ComponentWithChildViewContainer,
|
||||
PizzaMsg,
|
||||
DirectiveWithViewContainer,
|
||||
ContentElementDialog
|
||||
ContentElementDialog,
|
||||
DialogWithInjectedData
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [MdDialogModule],
|
||||
exports: TEST_DIRECTIVES,
|
||||
declarations: TEST_DIRECTIVES,
|
||||
entryComponents: [ComponentWithChildViewContainer, PizzaMsg, ContentElementDialog],
|
||||
entryComponents: [
|
||||
ComponentWithChildViewContainer,
|
||||
PizzaMsg,
|
||||
ContentElementDialog,
|
||||
DialogWithInjectedData
|
||||
],
|
||||
})
|
||||
class DialogTestModule { }
|
||||
|
||||
@@ -129,7 +129,7 @@ export class MdDialog {
|
||||
// to modify and close it.
|
||||
let dialogRef = <MdDialogRef<T>> new MdDialogRef(overlayRef);
|
||||
|
||||
if (!dialogContainer.dialogConfig.disableClose) {
|
||||
if (!config.disableClose) {
|
||||
// When the dialog backdrop is clicked, we want to close it.
|
||||
overlayRef.backdropClick().first().subscribe(() => dialogRef.close());
|
||||
}
|
||||
@@ -141,7 +141,7 @@ export class MdDialog {
|
||||
// inject the MdDialogRef. This allows a component loaded inside of a dialog to close itself
|
||||
// and, optionally, to return a value.
|
||||
let userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
|
||||
let dialogInjector = new DialogInjector(dialogRef, userInjector || this._injector);
|
||||
let dialogInjector = new DialogInjector(userInjector || this._injector, dialogRef, config.data);
|
||||
|
||||
let contentPortal = new ComponentPortal(component, null, dialogInjector);
|
||||
|
||||
|
||||
@@ -57,3 +57,4 @@ export * from './dialog-container';
|
||||
export * from './dialog-content-directives';
|
||||
export * from './dialog-config';
|
||||
export * from './dialog-ref';
|
||||
export {MD_DIALOG_DATA} from './dialog-injector';
|
||||
|
||||
Reference in New Issue
Block a user