diff --git a/src/components/angular2-modal/components/base-dynamic-component.ts b/src/components/angular2-modal/components/base-dynamic-component.ts index 2452174f..4048c44b 100644 --- a/src/components/angular2-modal/components/base-dynamic-component.ts +++ b/src/components/angular2-modal/components/base-dynamic-component.ts @@ -102,29 +102,16 @@ export class BaseDynamicComponent implements OnDestroy { */ protected _addComponent(type: any, vcRef: ViewContainerRef, - bindings?: ResolvedReflectiveProvider[]): ComponentRef { + bindings: ResolvedReflectiveProvider[] = [], + projectableNodes: any[][] = []): ComponentRef { const cmpRef = - createComponent(vcRef.injector.get(ComponentFactoryResolver), type, vcRef, bindings || []); + createComponent(vcRef.injector.get(ComponentFactoryResolver), type, vcRef, bindings, projectableNodes); cmpRef.changeDetectorRef.detectChanges(); return cmpRef; } - protected _addContent(content: string | TemplateRef, - vcRef: ViewContainerRef, - context: any): any[] { - - if (!content) return []; - - if (typeof content === 'string') { - return [[this.renderer.createText(null, `${content}`)]]; - } else if (content instanceof TemplateRef) { - return vcRef.createEmbeddedView(content, context).rootNodes; - } else { - - } - } private onEnd(event: TransitionEvent | AnimationEvent): void { diff --git a/src/components/angular2-modal/framework/createComponent.ts b/src/components/angular2-modal/framework/createComponent.ts index 6e41d86d..3af776b3 100644 --- a/src/components/angular2-modal/framework/createComponent.ts +++ b/src/components/angular2-modal/framework/createComponent.ts @@ -9,11 +9,13 @@ import { export function createComponent(cfr: ComponentFactoryResolver, type: any, vcr: ViewContainerRef, - bindings: ResolvedReflectiveProvider[]): ComponentRef { + bindings: ResolvedReflectiveProvider[], + projectableNodes?: any[][]): ComponentRef { return vcr.createComponent( cfr.resolveComponentFactory(type), vcr.length, - getInjector(vcr, bindings) + getInjector(vcr, bindings), + projectableNodes ); } diff --git a/src/components/angular2-modal/index.ts b/src/components/angular2-modal/index.ts index 507b05d6..29e80b9a 100644 --- a/src/components/angular2-modal/index.ts +++ b/src/components/angular2-modal/index.ts @@ -13,7 +13,8 @@ export { ModalComponent, OverlayRenderer, OverlayConfig, - CloseGuard + CloseGuard, + ContainerContent } from './models/tokens'; export { Modal, DOMOverlayRenderer } from './providers/index'; diff --git a/src/components/angular2-modal/models/tokens.ts b/src/components/angular2-modal/models/tokens.ts index 417e098d..d6c7f4f1 100644 --- a/src/components/angular2-modal/models/tokens.ts +++ b/src/components/angular2-modal/models/tokens.ts @@ -1,6 +1,8 @@ import { ComponentRef, ViewContainerRef, + TemplateRef, + Type, ResolvedReflectiveProvider } from '@angular/core'; @@ -17,6 +19,8 @@ export enum DROP_IN_TYPE { export type WideVCRef = ViewContainerRef | string; +export type ContainerContent = string | TemplateRef | Type; + export interface OverlayPlugin extends Function { (component: any, dialogRef: DialogRef, config: OverlayConfig): Maybe>; } diff --git a/src/components/angular2-modal/overlay/overlay.component.ts b/src/components/angular2-modal/overlay/overlay.component.ts index 721a7203..7b047e7a 100644 --- a/src/components/angular2-modal/overlay/overlay.component.ts +++ b/src/components/angular2-modal/overlay/overlay.component.ts @@ -1,15 +1,16 @@ declare const clearTimeout: any; import { - ApplicationRef, Component, ComponentRef, ElementRef, + EmbeddedViewRef, ResolvedReflectiveProvider, ViewChild, ViewContainerRef, ViewEncapsulation, - Renderer + Renderer, + TemplateRef } from '@angular/core'; import { PromiseCompleter, supportsKey } from '../framework/utils'; @@ -17,6 +18,11 @@ import { DialogRef } from '../models/dialog-ref'; import { BaseDynamicComponent } from '../components/index'; +interface ComponentLinkerData { + component: any; + bindings?: ResolvedReflectiveProvider[]; + projectableNodes?: any[][]; +} /** * Represents the modal overlay. */ @@ -26,14 +32,20 @@ import { BaseDynamicComponent } from '../components/index'; '(body:keydown)': 'documentKeypress($event)' }, encapsulation: ViewEncapsulation.None, - template: `` + template: +` + +` }) export class ModalOverlay extends BaseDynamicComponent { private beforeDestroyHandlers: Array<() => Promise>; - @ViewChild('vcRef', {read: ViewContainerRef}) private vcRef: ViewContainerRef; - + @ViewChild('innerView', {read: ViewContainerRef}) private innerVcr: ViewContainerRef; + @ViewChild('template') private template: TemplateRef; + constructor(private dialogRef: DialogRef, - private appRef: ApplicationRef, + private vcr: ViewContainerRef, el: ElementRef, renderer: Renderer) { super(el, renderer); @@ -41,8 +53,14 @@ export class ModalOverlay extends BaseDynamicComponent { } - addComponent(type: any, bindings?: ResolvedReflectiveProvider[]): ComponentRef { - return super._addComponent(type, this.vcRef, bindings); + addEmbeddedComponent(linkData: ComponentLinkerData): EmbeddedViewRef { + return this.vcr.createEmbeddedView(this.template, { + $implicit: linkData + }); + } + + addComponent(type: any, bindings: ResolvedReflectiveProvider[] = [], projectableNodes: any[][] = []): ComponentRef { + return super._addComponent(type, this.innerVcr, bindings, projectableNodes); } fullscreen(): void { diff --git a/src/components/angular2-modal/plugins/bootstrap/modal-container.component.ts b/src/components/angular2-modal/plugins/bootstrap/modal-container.component.ts index dfef8a41..a3fd082c 100644 --- a/src/components/angular2-modal/plugins/bootstrap/modal-container.component.ts +++ b/src/components/angular2-modal/plugins/bootstrap/modal-container.component.ts @@ -1,11 +1,7 @@ import { Component, ElementRef, - ViewChild, - ViewContainerRef, ViewEncapsulation, - ResolvedReflectiveProvider, - ComponentRef, Renderer } from '@angular/core'; @@ -27,20 +23,14 @@ import { MessageModalPreset } from'./presets/message-modal-preset'; [class.modal-lg]="dialog.context.size == \'lg\'" [class.modal-sm]="dialog.context.size == \'sm\'"> ` }) export class BSModalContainer extends BaseDynamicComponent { - @ViewChild('dlg', {read: ViewContainerRef}) private vcRef: ViewContainerRef; - - constructor(public dialog: DialogRef, + constructor(public dialog: DialogRef, el: ElementRef, renderer: Renderer) { super(el, renderer); this.activateAnimationListener(); } - - addComponent(type: any, bindings?: ResolvedReflectiveProvider[]): ComponentRef { - return super._addComponent(type, this.vcRef, bindings); - } } diff --git a/src/components/angular2-modal/plugins/bootstrap/modal.ts b/src/components/angular2-modal/plugins/bootstrap/modal.ts index c80b38da..8546f134 100644 --- a/src/components/angular2-modal/plugins/bootstrap/modal.ts +++ b/src/components/angular2-modal/plugins/bootstrap/modal.ts @@ -2,16 +2,18 @@ import 'rxjs/add/operator/combineLatest'; import { Injectable, - ResolvedReflectiveProvider as RRP + ResolvedReflectiveProvider as RRP, + ReflectiveInjector, + Renderer } from '@angular/core'; import { Maybe, + ContainerContent, Overlay, DialogRef, Modal as Modal_, CSSBackdrop, - CSSDialogContainer, PromiseCompleter } from '../../../../components/angular2-modal'; @@ -23,8 +25,8 @@ import { TwoButtonPresetBuilder } from './../bootstrap/presets/two-button-preset @Injectable() export class Modal extends Modal_ { - constructor(overlay: Overlay) { - super(overlay); + constructor(overlay: Overlay, renderer: Renderer) { + super(overlay, renderer); } alert(): OneButtonPresetBuilder { @@ -40,18 +42,15 @@ export class Modal extends Modal_ { } protected create(dialogRef: DialogRef, - type: any, + content: ContainerContent, bindings?: RRP[]): Maybe> { - let refs = this.createModal(dialogRef, CSSBackdrop, BSModalContainer); - - refs.containerRef - .instance.addComponent(type, bindings); - + const backdropRef = this.createBackdrop(dialogRef, CSSBackdrop); + const containerRef = this.createContainer(dialogRef, BSModalContainer, content, bindings); let overlay = dialogRef.overlayRef.instance; - let backdrop = refs.backdropRef.instance; - let container = refs.containerRef.instance; + let backdrop = backdropRef.instance; + let container = containerRef.instance; dialogRef.inElement ? overlay.insideElement() : overlay.fullscreen(); @@ -69,8 +68,8 @@ export class Modal extends Modal_ { backdrop.addClass('in'); container.addClass('in'); - if (refs.containerRef.location.nativeElement) { - refs.containerRef.location.nativeElement.focus(); + if (containerRef.location.nativeElement) { + containerRef.location.nativeElement.focus(); } overlay.beforeDestroy(() => { diff --git a/src/components/angular2-modal/providers/modal.ts b/src/components/angular2-modal/providers/modal.ts index a7ec01d1..763da824 100644 --- a/src/components/angular2-modal/providers/modal.ts +++ b/src/components/angular2-modal/providers/modal.ts @@ -1,12 +1,13 @@ import { ComponentRef, + TemplateRef, ReflectiveInjector, - ResolvedReflectiveProvider + ResolvedReflectiveProvider, Type, Renderer } from '@angular/core'; import { Overlay } from '../overlay/index'; import { Class, Maybe } from '../framework/utils'; -import { OverlayConfig } from '../models/tokens'; +import { OverlayConfig, ContainerContent } from '../models/tokens'; import { DialogRef } from '../models/dialog-ref'; import { ModalControllingContextBuilder } from '../models/overlay-context'; @@ -18,7 +19,7 @@ export class UnsupportedDropInError extends Error { } export abstract class Modal { - constructor(public overlay: Overlay) { } + constructor(public overlay: Overlay, private renderer: Renderer) { } alert(): ModalControllingContextBuilder { @@ -35,11 +36,11 @@ export abstract class Modal { /** * Opens a modal window inside an existing component. - * @param componentType The angular Component to render as the modal content. + * @param content The content to display, either string, template ref or a component. * @param config Additional settings. * @returns {Promise} */ - open(componentType: any, config?: OverlayConfig): Promise> { + open(content: ContainerContent, config?: OverlayConfig): Promise> { config = config || {} as any; try { let dialogs = this.overlay.open(config, this.constructor); @@ -52,7 +53,7 @@ export abstract class Modal { // TODO: Currently supporting 1 view container, hence working on dialogs[0]. // upgrade to multiple containers. return Promise.resolve( - this.create(dialogs[0], componentType, config.bindings) + this.create(dialogs[0], content, config.bindings) ); } catch (e) { @@ -69,16 +70,44 @@ export abstract class Modal { * @returns {MaybeDialogRef} */ protected abstract create(dialogRef: DialogRef, - type: any, + type: ContainerContent, bindings?: ResolvedReflectiveProvider[]): Maybe>; + protected createBackdrop(dialogRef: DialogRef, BackdropComponent: Class): ComponentRef { + const b = ReflectiveInjector.resolve([{provide: DialogRef, useValue: dialogRef}]); + return dialogRef.overlayRef.instance.addComponent(BackdropComponent, b); + } + + protected createContainer( + dialogRef: DialogRef, + ContainerComponent: Class, + content: string | TemplateRef | Type, + bindings?: ResolvedReflectiveProvider[]): ComponentRef { + + const b = ReflectiveInjector.resolve([{provide: DialogRef, useValue: dialogRef}]) + .concat(bindings || []); + + let nodes: any[]; + if (typeof content === 'string') { + nodes = [[this.renderer.createText(null, `${content}`)]]; + } else if (content instanceof TemplateRef) { + nodes = [this.overlay.defaultViewContainer.createEmbeddedView(content, dialogRef.context).rootNodes]; + } else { + nodes = [dialogRef.overlayRef.instance.addEmbeddedComponent({ component: content, bindings: b }).rootNodes]; + } + return dialogRef.overlayRef.instance.addComponent(ContainerComponent, b, nodes); + } + + /** * A helper function for derived classes to create backdrop & container * @param dialogRef * @param backdrop * @param container * @returns { backdropRef: ComponentRef, containerRef: ComponentRef } + * + * @deprecated use createBackdrop and createContainer instead */ protected createModal(dialogRef: DialogRef, backdrop: Class, container: Class) : { backdropRef: ComponentRef, containerRef: ComponentRef } {