From be0da096eac2a30f85380e4f30173bca903988d4 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Thu, 19 Jan 2017 06:34:33 +0100 Subject: [PATCH] fix(dialog): use injector from viewContainerRef if provided (#2655) * Right now the `MdDialog` always instantiates the user-provided component with the injector from the `MdDialog` service. This is not valid, because developers can provide the `viewContainerRef` to create their dialog in the desired component structure and also expect the parent injector to be the same as in the `viewContainerRef`. --- src/lib/dialog/dialog.spec.ts | 20 ++++++++++++++++++-- src/lib/dialog/dialog.ts | 9 ++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/lib/dialog/dialog.spec.ts b/src/lib/dialog/dialog.spec.ts index 6c81e45b682e..5cc05dd3d70b 100644 --- a/src/lib/dialog/dialog.spec.ts +++ b/src/lib/dialog/dialog.spec.ts @@ -8,7 +8,7 @@ import { tick, } from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {NgModule, Component, Directive, ViewChild, ViewContainerRef} from '@angular/core'; +import {NgModule, Component, Directive, ViewChild, ViewContainerRef, Injector} from '@angular/core'; import {MdDialogModule} from './index'; import {MdDialog} from './dialog'; import {OverlayContainer} from '../core'; @@ -64,6 +64,21 @@ describe('MdDialog', () => { expect(dialogContainerElement.getAttribute('role')).toBe('dialog'); }); + it('should use injector from viewContainerRef for DialogInjector', () => { + let dialogRef = dialog.open(PizzaMsg, { + viewContainerRef: testViewContainerRef + }); + + viewContainerFixture.detectChanges(); + + let dialogInjector = dialogRef.componentInstance.dialogInjector; + + expect(dialogRef.componentInstance.dialogRef).toBe(dialogRef); + expect(dialogInjector.get(DirectiveWithViewContainer)).toBeTruthy( + 'Expected the dialog component to be created with the injector from the viewContainerRef.' + ); + }); + it('should open a dialog with a component and no ViewContainerRef', () => { let dialogRef = dialog.open(PizzaMsg); @@ -435,7 +450,8 @@ class ComponentWithChildViewContainer { /** Simple component for testing ComponentPortal. */ @Component({template: '

Pizza

'}) class PizzaMsg { - constructor(public dialogRef: MdDialogRef) { } + constructor(public dialogRef: MdDialogRef, + public dialogInjector: Injector) {} } @Component({ diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index 38c51ef6be59..17f61bcf7064 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -42,7 +42,7 @@ export class MdDialog { let overlayRef = this._createOverlay(config); let dialogContainer = this._attachDialogContainer(overlayRef, config); - let dialogRef = this._attachDialogContent(component, dialogContainer, overlayRef); + let dialogRef = this._attachDialogContent(component, dialogContainer, overlayRef, config); this._openDialogs.push(dialogRef); dialogRef.afterClosed().subscribe(() => this._removeOpenDialog(dialogRef)); @@ -96,12 +96,14 @@ export class MdDialog { * @param component The type of component being loaded into the dialog. * @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, dialogContainer: MdDialogContainer, - overlayRef: OverlayRef): MdDialogRef { + overlayRef: OverlayRef, + 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. let dialogRef = > new MdDialogRef(overlayRef); @@ -117,7 +119,8 @@ export class MdDialog { // We create an injector specifically for the component we're instantiating so that it can // inject the MdDialogRef. This allows a component loaded inside of a dialog to close itself // and, optionally, to return a value. - let dialogInjector = new DialogInjector(dialogRef, this._injector); + let userInjector = config && config.viewContainerRef && config.viewContainerRef.injector; + let dialogInjector = new DialogInjector(dialogRef, userInjector || this._injector); let contentPortal = new ComponentPortal(component, null, dialogInjector);