diff --git a/src/component-loader/component-loader.class.ts b/src/component-loader/component-loader.class.ts index 7a2c4ddae8..49fe60c199 100644 --- a/src/component-loader/component-loader.class.ts +++ b/src/component-loader/component-loader.class.ts @@ -2,13 +2,23 @@ // todo: merge events onShow, onShown, etc... // todo: add global positioning configuration? import { - NgZone, ViewContainerRef, ComponentFactoryResolver, Injector, Renderer, - ElementRef, ComponentRef, ComponentFactory, Type, TemplateRef, EventEmitter, - Provider, ReflectiveInjector + ComponentFactory, + ComponentFactoryResolver, + ComponentRef, + ElementRef, + EventEmitter, + Injector, + NgZone, + Provider, + ReflectiveInjector, + Renderer, + TemplateRef, + Type, + ViewContainerRef } from '@angular/core'; -import { ContentRef } from './content-ref.class'; -import { PositioningService, PositioningOptions } from '../positioning'; +import { PositioningOptions, PositioningService } from '../positioning'; import { listenToTriggers } from '../utils/triggers'; +import { ContentRef } from './content-ref.class'; export interface ListenOptions { target?: ElementRef; @@ -112,7 +122,7 @@ export class ComponentLoader { return this; } - public show(opts: {content?: string | TemplateRef, [key:string]: any} = {}): ComponentRef { + public show(opts: { content?: string | TemplateRef, [key: string]: any } = {}): ComponentRef { this._subscribePositioning(); this._innerComponent = null; @@ -191,8 +201,8 @@ export class ComponentLoader { listenOpts.show = listenOpts.show || (() => this.show()); listenOpts.hide = listenOpts.hide || (() => this.hide()); listenOpts.toggle = listenOpts.toggle || (() => this.isShown - ? listenOpts.hide() - : listenOpts.show()); + ? listenOpts.hide() + : listenOpts.show()); this._unregisterListenersFn = listenToTriggers( this._renderer, diff --git a/src/modal/bs-modal-factory.service.ts b/src/modal/bs-modal-factory.service.ts new file mode 100644 index 0000000000..7b2ddb6874 --- /dev/null +++ b/src/modal/bs-modal-factory.service.ts @@ -0,0 +1,9 @@ +import { ElementRef, Injectable, Renderer, ViewContainerRef } from '@angular/core'; +import { BsModalService } from './bs-modal.service'; + +@Injectable() +export class BsModalFactory { + constructor(public modalService: BsModalService, private vcRef: ViewContainerRef) { + this.modalService.create(null, this.vcRef, null); + } +} diff --git a/src/modal/bs-modal.service.ts b/src/modal/bs-modal.service.ts index abf33982d5..1abd2849a5 100644 --- a/src/modal/bs-modal.service.ts +++ b/src/modal/bs-modal.service.ts @@ -1,9 +1,10 @@ import { ComponentRef, ElementRef, Injectable, Renderer, TemplateRef, ViewContainerRef } from '@angular/core'; + import { ComponentLoader } from '../component-loader/component-loader.class'; -import { ModalBackdropComponent } from './modal-backdrop.component'; -import { ModalContainerComponent } from './modal-container.component'; import { ComponentLoaderFactory } from '../component-loader/component-loader.factory'; import { Utils } from '../utils/utils.class'; +import { ModalBackdropComponent } from './modal-backdrop.component'; +import { ModalContainerComponent } from './modal-container.component'; import { BsModalRef, modalConfigDefaults, ModalOptions } from './modal-options.class'; const TRANSITION_DURATION = 300; @@ -16,9 +17,10 @@ export class BsModalService { public config: ModalOptions = modalConfigDefaults; protected _isShown: boolean = false; protected timerRmBackDrop: number = 0; - protected backdrop: ComponentRef; + protected backdropRef: ComponentRef; private _backdrop: ComponentLoader; private _modal: ComponentLoader; + public constructor(private clf: ComponentLoaderFactory) {} /** Initialization of BsModalService, requires ElementRef, ViewContainerRef and Renderer instances */ @@ -34,76 +36,69 @@ export class BsModalService { this.config = Object.assign({}, modalConfigDefaults, config); clearTimeout(this.timerRmBackDrop); this._isShown = true; - this.showBackdrop(); + this.toggleBackdrop(); const bsModalRef = new BsModalRef(); const modalContainerRef = this._modal .provide({provide: ModalOptions, useValue: this.config}) .provide({provide: BsModalRef, useValue: bsModalRef}) .attach(ModalContainerComponent) .show({content}); - bsModalRef.hide = () => {modalContainerRef.instance.hide()}; + bsModalRef.hide = () => {modalContainerRef.instance.hide();}; bsModalRef.content = this._modal.getInnerComponent() || null; return bsModalRef; } public hide() { this._isShown = false; - if (this.backdrop && this.backdrop.instance) { - this.backdrop.instance.isShown = false; + if (this.backdropRef && this.backdropRef.instance) { + this.backdropRef.instance.isShown = false; } setTimeout(() => { this.removeBackdrop(); if (this._modal) { this._modal.hide(); } - this.backdrop = null; + this.backdropRef = null; }, BACKDROP_TRANSITION_DURATION); } - /** @internal */ - protected showBackdrop(callback?: Function): void { - if (this._isShown && (this.config.backdrop || this.config.backdrop === 'static') && (!this.backdrop || !this.backdrop.instance.isShown)) { - this.removeBackdrop(); - this._backdrop - .attach(ModalBackdropComponent) - .to('body') - .show({isAnimated: false}); - this.backdrop = this._backdrop._componentRef; - - if (this.isAnimated) { - this.backdrop.instance.isAnimated = this.isAnimated; - Utils.reflow(this.backdrop.instance.element.nativeElement); - } - this.backdrop.instance.isShown = true; - if (!callback) { - return; - } + /** @internal */ + protected toggleBackdrop(): void { + // this if will not happen + if (!this._isShown && this.backdropRef) { + return this._hideBackdrop(); + } - if (!this.isAnimated) { - callback(); - return; - } + const isBackdropEnabled = this.config.backdrop || this.config.backdrop === 'static'; + const isBackdropInDOM = !this.backdropRef || !this.backdropRef.instance.isShown; + if (this._isShown && isBackdropEnabled && isBackdropInDOM) { + return this._showBackdrop(); + } + } - setTimeout(callback, BACKDROP_TRANSITION_DURATION); - } else if (!this._isShown && this.backdrop) { - this.backdrop.instance.isShown = false; + _showBackdrop(): void { + this.removeBackdrop(); + this._backdrop + .attach(ModalBackdropComponent) + .to('body') + // .show({isAnimated: false}); + .show({isAnimated: this.isAnimated}); + this.backdropRef = this._backdrop._componentRef; - let callbackRemove = () => { - this.removeBackdrop(); - if (callback) { - callback(); - } - }; + // if (this.isAnimated) { + // this.backdropRef.instance.isAnimated = this.isAnimated; + // Utils.reflow(this.backdropRef.instance.element.nativeElement); + // } + // + // this.backdropRef.instance.isShown = true; + } - if (this.backdrop.instance.isAnimated) { - this.timerRmBackDrop = setTimeout(callbackRemove, BACKDROP_TRANSITION_DURATION); - } else { - callbackRemove(); - } - } else if (callback) { - callback(); - } + _hideBackdrop(): void { + this.backdropRef.instance.isShown = false; + const duration = this.backdropRef.instance.isAnimated ? BACKDROP_TRANSITION_DURATION: 0; + this.timerRmBackDrop = setTimeout(() => this.removeBackdrop(), duration); } + protected removeBackdrop(): void { this._backdrop.hide(); } diff --git a/src/modal/index.ts b/src/modal/index.ts index 6cd0f2515a..86a5f0a1ce 100644 --- a/src/modal/index.ts +++ b/src/modal/index.ts @@ -1,6 +1,7 @@ -export {ModalContainerComponent} from './modal-container.component'; -export {ModalBackdropComponent, ModalBackdropOptions} from './modal-backdrop.component'; -export {ModalOptions} from './modal-options.class'; -export {ModalDirective} from './modal.component'; -export {ModalModule} from './modal.module'; -export {BsModalService} from './bs-modal.service'; +export { ModalContainerComponent } from './modal-container.component'; +export { ModalBackdropComponent, ModalBackdropOptions } from './modal-backdrop.component'; +export { ModalOptions, BsModalRef } from './modal-options.class'; +export { ModalDirective } from './modal.component'; +export { ModalModule } from './modal.module'; +export { BsModalService } from './bs-modal.service'; +export { BsModalFactory } from './bs-modal-factory.service'; diff --git a/src/modal/modal-backdrop.component.ts b/src/modal/modal-backdrop.component.ts index 0edb453640..8e4481b99c 100644 --- a/src/modal/modal-backdrop.component.ts +++ b/src/modal/modal-backdrop.component.ts @@ -1,12 +1,13 @@ -import { Component, ElementRef, Renderer } from '@angular/core'; +import { Component, ElementRef, OnInit, Renderer } from '@angular/core'; import { ClassName } from './modal-options.class'; import { isBs3 } from '../utils/ng2-bootstrap-config'; +import { Utils } from '../utils/utils.class'; export class ModalBackdropOptions { - public animate:boolean = true; + public animate: boolean = true; - public constructor(options:ModalBackdropOptions) { + public constructor(options: ModalBackdropOptions) { Object.assign(this, options); } } @@ -18,21 +19,21 @@ export class ModalBackdropOptions { // tslint:disable-next-line host: {'class': ClassName.BACKDROP} }) -export class ModalBackdropComponent { - public get isAnimated():boolean { +export class ModalBackdropComponent implements OnInit { + public get isAnimated(): boolean { return this._isAnimated; } - public set isAnimated(value:boolean) { + public set isAnimated(value: boolean) { this._isAnimated = value; - this.renderer.setElementClass(this.element.nativeElement, `${ClassName.FADE}`, value); + // this.renderer.setElementClass(this.element.nativeElement, `${ClassName.FADE}`, value); } - public get isShown():boolean { + public get isShown(): boolean { return this._isShown; } - public set isShown(value:boolean) { + public set isShown(value: boolean) { this._isShown = value; this.renderer.setElementClass(this.element.nativeElement, `${ClassName.IN}`, value); if (!isBs3()) { @@ -40,14 +41,22 @@ export class ModalBackdropComponent { } } - public element:ElementRef; - public renderer:Renderer; + public element: ElementRef; + public renderer: Renderer; - protected _isAnimated:boolean; - protected _isShown:boolean = false; + protected _isAnimated: boolean; + protected _isShown = false; - public constructor(element:ElementRef, renderer:Renderer) { + public constructor(element: ElementRef, renderer: Renderer) { this.element = element; this.renderer = renderer; } + + ngOnInit(): void { + if (this.isAnimated) { + this.renderer.setElementClass(this.element.nativeElement, `${ClassName.FADE}`, this.isAnimated); + Utils.reflow(this.element.nativeElement); + } + this.isShown = true; + } } diff --git a/src/modal/modal.module.ts b/src/modal/modal.module.ts index d692a5dcbb..e8300d3100 100644 --- a/src/modal/modal.module.ts +++ b/src/modal/modal.module.ts @@ -6,15 +6,16 @@ import { PositioningService } from '../positioning'; import { ComponentLoaderFactory } from '../component-loader'; import { ModalContainerComponent } from './modal-container.component'; import { BsModalService } from './bs-modal.service'; +import { BsModalFactory } from './bs-modal-factory.service'; @NgModule({ declarations: [ModalBackdropComponent, ModalDirective, ModalContainerComponent], exports: [ModalBackdropComponent, ModalDirective], - providers: [BsModalService, ComponentLoaderFactory], + // providers: [BsModalService, ComponentLoaderFactory], entryComponents: [ModalBackdropComponent, ModalContainerComponent] }) export class ModalModule { public static forRoot(): ModuleWithProviders { - return {ngModule: ModalModule, providers: [ComponentLoaderFactory, PositioningService]}; + return {ngModule: ModalModule, providers: [BsModalFactory, BsModalService, ComponentLoaderFactory, PositioningService]}; } }