diff --git a/README.md b/README.md index 02a5bc2..48505fe 100644 --- a/README.md +++ b/README.md @@ -101,13 +101,21 @@ Feel free to request more. #### Outputs +- `onShow: EventEmitter` + + Emits when the `show.bs.modal` event is triggered, just before the modal is shown. Call `Event.preventDefault()` to cancel the modal from showing. + +- `onHide: EventEmitter` + + Emits when the `hide.bs.modal` event is triggered, just before the modal is hidden. Call `BsModalHideEvent.event.preventDefault()` to cancel the modal from hiding. + - `onClose: EventEmitter` Emits when `ModalComponent.close()` is called. Will emit whatever was passed into `ModalComponent.close()`. -- `onDismiss: EventEmitter` +- `onDismiss: EventEmitter` - Emits when `ModalComponent.dismiss()` is called, or when the modal is dismissed with the keyboard or backdrop. Returns a `BsModalCloseSource` that can be used to determine how the modal was dismissed. + Emits when `ModalComponent.dismiss()` is called, or when the modal is dismissed with the keyboard or backdrop. Returns a `BsModalHideType` that can be used to determine how the modal was dismissed. - `onOpen: EventEmitter` @@ -157,7 +165,7 @@ Feel free to request more. - `dismissAll(): void` - Dismiss all open modals. + Dismiss all open modals. Inject the `BsModalService` into a componet/service to use. ## Example Usage diff --git a/src/demo/app/modal-demo.component.html b/src/demo/app/modal-demo.component.html index ff69e2e..a872d7e 100644 --- a/src/demo/app/modal-demo.component.html +++ b/src/demo/app/modal-demo.component.html @@ -18,6 +18,7 @@

Common Usage

+


@@ -31,11 +32,20 @@

Other Usages


+

Intercepting events

+
+

+ + + | +

+
+

Output

{{ output }}
- + @@ -45,12 +55,31 @@ {{ item }} -

Selected: {{ selected }}

+

Selected: + {{ selected }} +

- + + + + + +

Selected: + {{ selected }} +

+
+ +
+ + @@ -64,13 +93,16 @@ - + -

Note: My z-index is set to 1049.

+

+ Note: My + z-index is set to + 1049.

@@ -79,7 +111,7 @@
- @@ -90,7 +122,7 @@ -
@@ -112,4 +144,49 @@
+ + + + + + +

+ Note: Keyboard and backdrop events cannot be prevented with + event.preventDefault(). Use the + keyboard and + backdrop options. +

+ +

Selected: + {{ selected }} +

+ +
+ +
+ + + + + + + +

Selected: + {{ selected }} +

+
+ +
+ + diff --git a/src/demo/app/modal-demo.component.ts b/src/demo/app/modal-demo.component.ts index 1c82c06..4005e09 100644 --- a/src/demo/app/modal-demo.component.ts +++ b/src/demo/app/modal-demo.component.ts @@ -1,6 +1,6 @@ -import {Component, ViewChild, ViewEncapsulation} from '@angular/core'; +import { Component, ViewChild, ViewEncapsulation } from '@angular/core'; import { Router } from '@angular/router'; -import { BsModalComponent, BsModalService } from '../../ng2-bs3-modal/ng2-bs3-modal'; +import { BsModalComponent, BsModalService, BsModalHideType } from '../../ng2-bs3-modal/ng2-bs3-modal'; @Component({ moduleId: module.id, @@ -36,6 +36,7 @@ export class ModalDemoComponent { keyboard = true; backdrop: string | boolean = true; css = false; + intercept = true; constructor(private router: Router, private modalservice: BsModalService) { } @@ -43,8 +44,8 @@ export class ModalDemoComponent { this.output = '(closed) ' + this.selected; } - dismissed() { - this.output = '(dismissed)'; + dismissed(type) { + this.output = `(dismissed) ${BsModalHideType[type]}`; } opened() { @@ -62,6 +63,20 @@ export class ModalDemoComponent { dismissAll() { this.modalservice.dismissAll(); } + + interceptDismiss(e) { + if (this.intercept && e.type === BsModalHideType.Dismiss) { + e.event.preventDefault(); + this.output = '(intercepted) Dismiss'; + } + } + + interceptOpen(e) { + if (this.intercept) { + e.preventDefault(); + this.output = '(intercepted) Open'; + } + } } export class Person { diff --git a/src/ng2-bs3-modal/modal/modal-service.ts b/src/ng2-bs3-modal/modal/modal-service.ts index d6746f5..b912b9c 100644 --- a/src/ng2-bs3-modal/modal/modal-service.ts +++ b/src/ng2-bs3-modal/modal/modal-service.ts @@ -4,39 +4,46 @@ import 'rxjs/add/observable/fromEvent'; import 'rxjs/add/operator/filter'; import { BsModalComponent } from './modal'; -import { BsModalCloseSource } from './models'; +import { BsModalHideType } from './models'; import { JQueryStyleEventEmitter } from 'rxjs/observable/FromEventObservable'; const EVENT_SUFFIX = 'ng2-bs3-modal'; const KEYUP_EVENT_NAME = `keyup.${EVENT_SUFFIX}`; const CLICK_EVENT_NAME = `click.${EVENT_SUFFIX}`; +const SHOW_EVENT_NAME = `show.bs.modal.${EVENT_SUFFIX}`; @Injectable() export class BsModalService { private modals: BsModalComponent[] = []; + private $body: JQuery; - public onBackdropClose: Observable; - public onKeyboardClose: Observable; + public onBackdropClose$: Observable; + public onKeyboardClose$: Observable; + public onModalStack$: Observable; constructor() { - this.onBackdropClose = Observable.fromEvent(jQuery(document) as JQueryStyleEventEmitter, CLICK_EVENT_NAME) - .filter((e: MouseEvent) => e.target === jQuery('.modal')[0]) - .map(() => BsModalCloseSource.Backdrop) + this.$body = jQuery(document.body); + + this.onBackdropClose$ = Observable.fromEvent(this.$body as JQueryStyleEventEmitter, CLICK_EVENT_NAME) + .filter((e: MouseEvent) => jQuery(e.target).is('.modal')) + .map(() => BsModalHideType.Backdrop) .share(); - this.onKeyboardClose = Observable.fromEvent(jQuery(document) as JQueryStyleEventEmitter, KEYUP_EVENT_NAME) + this.onKeyboardClose$ = Observable.fromEvent(this.$body as JQueryStyleEventEmitter, KEYUP_EVENT_NAME) .filter((e: KeyboardEvent) => e.which === 27) - .map(() => BsModalCloseSource.Keyboard) + .map(() => BsModalHideType.Keyboard) .share(); - jQuery(document).on('show.bs.modal', '.modal', function () { - const zIndex = 1040 + (10 * $('.modal:visible').length); - $(this).css('z-index', zIndex); - setTimeout(function() { - $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'); - }, 0); - }); + this.onModalStack$ = Observable.fromEvent(this.$body as JQueryStyleEventEmitter, SHOW_EVENT_NAME) + .do(() => { + const zIndex = 1040 + (10 * $('.modal:visible').length); + $(this).css('z-index', zIndex); + setTimeout(function() { + $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'); + }, 0); + }) + .share(); } public add(modal: BsModalComponent) { @@ -50,7 +57,10 @@ export class BsModalService { public focusNext() { const visible = this.modals.filter(m => m.visible); - if (visible.length) visible[visible.length - 1].focus(); + if (visible.length) { + this.$body.addClass('modal-open'); + visible[visible.length - 1].focus(); + } } public dismissAll() { diff --git a/src/ng2-bs3-modal/modal/modal.ts b/src/ng2-bs3-modal/modal/modal.ts index 54daeac..f4ac001 100644 --- a/src/ng2-bs3-modal/modal/modal.ts +++ b/src/ng2-bs3-modal/modal/modal.ts @@ -1,8 +1,9 @@ import { Component, + OnInit, + AfterViewInit, OnChanges, OnDestroy, - AfterViewInit, Input, Output, EventEmitter, @@ -14,20 +15,23 @@ import { import { Observable } from 'rxjs/Observable'; import { Observer } from 'rxjs/Observer'; import { Subject } from 'rxjs/Subject'; +import { Subscription } from 'rxjs/Subscription'; import { JQueryStyleEventEmitter } from 'rxjs/observable/FromEventObservable'; +import 'rxjs/add/observable/empty'; import 'rxjs/add/observable/fromEvent'; import 'rxjs/add/observable/merge'; +import 'rxjs/add/observable/of'; import 'rxjs/add/observable/zip'; import 'rxjs/add/operator/do'; -import 'rxjs/add/operator/first'; +import 'rxjs/add/operator/filter'; import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/partition'; import 'rxjs/add/operator/share'; +import 'rxjs/add/operator/take'; import 'rxjs/add/operator/toPromise'; +import 'rxjs/add/operator/catch'; -import { BsModalCloseEvent, BsModalCloseSource, BsModalOptions, BsModalSize } from './models'; +import { BsModalHideEvent, BsModalHideType, BsModalOptions, BsModalSize } from './models'; import { BsModalService } from './modal-service'; -import '../utils/to-event-emitter'; const EVENT_SUFFIX = 'ng2-bs3-modal'; const SHOW_EVENT_NAME = `show.bs.modal.${EVENT_SUFFIX}`; @@ -47,15 +51,22 @@ const DATA_KEY = 'bs.modal'; ` }) -export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { +export class BsModalComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { private overrideSize: string = null; private $modal: JQuery; private $dialog: JQuery; - private onManualClose: Subject<{}> = new Subject<{}>(); - private onShown: Observable<{}>; - private onHidden: Observable; - private onCloseInternal: Observable; + private onShowEvent$: Observable; + private onShownEvent$: Observable; + private onHideEvent$: Observable; + private onHiddenEvent$: Observable; + private onLoadedEvent$: Observable; + private onShown$: Observable<{}>; + private onInternalClose$: Subject = new Subject(); + private onDismiss$: Observable; + private onHide$: Observable; + private onHidden$: Observable; + private subscriptions: Subscription[] = []; private get options() { if (!this.$modal) this.init(); return this.$modal.data(DATA_KEY).options; @@ -69,12 +80,12 @@ export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { @Input() public size: string; @Input() public cssClass: string; + @Output() public onShow: EventEmitter = new EventEmitter(); + @Output() public onOpen: EventEmitter = new EventEmitter(); + @Output() public onHide: EventEmitter = new EventEmitter(); @Output() public onClose: EventEmitter = new EventEmitter(); - @Output() public onDismiss: EventEmitter; - @Output() public onOpen: EventEmitter; - @Output() public onShow: EventEmitter; - @Output() public onHide: EventEmitter; - @Output() public onLoaded: EventEmitter; + @Output() public onDismiss: EventEmitter = new EventEmitter(); + @Output() public onLoaded: EventEmitter = new EventEmitter(); @HostBinding('class.fade') get fadeClass() { return this.animation; } @@ -93,6 +104,14 @@ export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { this.init(); } + public ngOnInit() { + this.wireUpEventEmitters(); + } + + public ngAfterViewInit() { + this.$dialog = this.$modal.find('.modal-dialog'); + } + public ngOnChanges() { this.setOptions({ backdrop: this.backdrop, @@ -101,14 +120,8 @@ export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { } public ngOnDestroy() { - this.service.remove(this); - return this.hide().do(() => { - if (this.$modal) { - this.$modal.data(DATA_KEY, null); - this.$modal.remove(); - this.$modal = null; - } - }).toPromise(); + this.onInternalClose$.next(BsModalHideType.Destroy); + return this.destroy(); } public triggerTransitionEnd() { @@ -119,29 +132,27 @@ export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { this.$modal.trigger('focus'); } - public ngAfterViewInit() { - this.$dialog = this.$modal.find('.modal-dialog'); - } - public routerCanDeactivate(): any { - return this.ngOnDestroy(); + this.onInternalClose$.next(BsModalHideType.RouteChange); + return this.destroy(); } public open(size?: string) { + this.overrideSize = null; if (BsModalSize.isValidSize(size)) this.overrideSize = size; return this.show().toPromise(); } public close(value?: any): Promise<{}> { - this.onManualClose.next(BsModalCloseSource.Confirm); + this.onInternalClose$.next(BsModalHideType.Close); return this.hide() .do(() => this.onClose.emit(value)) .toPromise() - .then(() => value) + .then(() => value); } public dismiss(): Promise<{}> { - this.onManualClose.next(BsModalCloseSource.Dismiss); + this.onInternalClose$.next(BsModalHideType.Dismiss); return this.hide().toPromise(); } @@ -175,84 +186,103 @@ export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { || this.overrideSize === BsModalSize.Large; } - private show(): Observable<{}> { + private show(): Observable { + if (this.visible) return Observable.of(null); + return Observable.create((o: Observer) => { - if (!this.visible) { - this.onShown.first().subscribe((next) => { - o.next(next); - o.complete(); - }); - - // Fix for shown.bs.modal not firing when .fade is present - // https://github.com/twbs/bootstrap/issues/11793 - if (this.animation) { - this.$dialog.one('transitionend', () => { - this.$modal.trigger('focus').trigger(SHOWN_EVENT_NAME); - }); - } - - this.$modal.modal('show'); - } - else { - o.next(null); + this.onShown$.take(1).subscribe(next => { + o.next(next); o.complete(); - } + }); + + this.transitionFix(); + this.$modal.modal('show'); }); } - private hide(): Observable { - return Observable.create((o: Observer) => { - if (this.visible) { - this.onHidden.first().subscribe((next) => { - o.next(next); - o.complete(); - }); - this.$modal.modal('hide'); - } - else { - o.next(null); + private transitionFix() { + // Fix for shown.bs.modal not firing when .fade is present + // https://github.com/twbs/bootstrap/issues/11793 + if (this.animation) { + this.$dialog.one('transitionend', () => { + this.$modal.trigger('focus').trigger(SHOWN_EVENT_NAME); + }); + } + } + + private hide(): Observable { + if (!this.visible) return Observable.of(null); + + return Observable.create((o: Observer) => { + this.onHidden$.take(1).subscribe(next => { + o.next(next); o.complete(); - } + }); + + this.$modal.modal('hide'); }); } private init() { this.$modal = jQuery(this.element.nativeElement); - this.$modal.appendTo('body'); + this.$modal.appendTo(document.body); this.$modal.modal({ show: false }); - const onHideEvent = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, HIDE_EVENT_NAME); - const onHiddenEvent = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, HIDDEN_EVENT_NAME); + this.onShowEvent$ = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, SHOW_EVENT_NAME); + this.onShownEvent$ = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, SHOWN_EVENT_NAME); + this.onHideEvent$ = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, HIDE_EVENT_NAME); + this.onHiddenEvent$ = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, HIDDEN_EVENT_NAME); + this.onLoadedEvent$ = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, LOADED_EVENT_NAME); - const onClose = Observable - .merge(this.onManualClose, this.service.onBackdropClose, this.service.onKeyboardClose) - .share(); + const onClose$ = Observable + .merge(this.onInternalClose$, this.service.onBackdropClose$, this.service.onKeyboardClose$) + .filter(() => this.visible); - this.onHide = Observable.zip(onHideEvent, onClose) - .map(x => { event: x[0], type: x[1] }) - .toEventEmitter(this.zone); + this.onHide$ = Observable.zip(this.onHideEvent$, onClose$) + .map(x => { event: x[0], type: x[1] }); - this.onHidden = Observable.zip(onHiddenEvent, onClose) + this.onHidden$ = Observable.zip(this.onHiddenEvent$, onClose$) .map(x => x[1]) .do(this.setVisible(false)) .do(() => this.service.focusNext()) .share(); - this.onShow = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, SHOW_EVENT_NAME) - .toEventEmitter(this.zone); - - this.onShown = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, SHOWN_EVENT_NAME) + this.onShown$ = this.onShownEvent$ .do(this.setVisible(true)) .share(); - const [closed, dismissed] = this.onHidden.partition((x) => x === BsModalCloseSource.Confirm); + this.onDismiss$ = this.onHidden$ + .filter((x) => x !== BsModalHideType.Close); + + // Start watching for events + this.subscriptions.push(...[ + this.onShown$.subscribe(() => { }), + this.onHidden$.subscribe(() => { }), + this.service.onModalStack$.subscribe(() => { }) + ]); + } + + private wireUpEventEmitters() { - this.onCloseInternal = closed; - this.onDismiss = dismissed.toEventEmitter(this.zone); - this.onOpen = this.onShown.toEventEmitter(this.zone); - this.onLoaded = Observable.fromEvent(this.$modal as JQueryStyleEventEmitter, LOADED_EVENT_NAME).toEventEmitter(this.zone); + this.wireUpEventEmitter(this.onShow, this.onShowEvent$); + this.wireUpEventEmitter(this.onOpen, this.onShown$); + this.wireUpEventEmitter(this.onHide, this.onHide$); + this.wireUpEventEmitter(this.onDismiss, this.onDismiss$); + this.wireUpEventEmitter(this.onLoaded, this.onLoadedEvent$); + } + + private wireUpEventEmitter(emitter: EventEmitter, stream$: Observable) { + if (emitter.observers.length === 0) return; + + const sub = stream$.subscribe((next) => { + this.zone.run(() => { + emitter.next(next); + }); + }); + + this.subscriptions.push(sub); } private setVisible = (isVisible) => { @@ -269,4 +299,17 @@ export class BsModalComponent implements OnDestroy, OnChanges, AfterViewInit { if (options.backdrop !== undefined) this.options.backdrop = backdrop; if (options.keyboard !== undefined) this.options.keyboard = options.keyboard; } + + private destroy() { + return this.hide().do(() => { + this.service.remove(this); + this.subscriptions.forEach(s => s.unsubscribe()); + this.subscriptions = []; + if (this.$modal) { + this.$modal.data(DATA_KEY, null); + this.$modal.remove(); + this.$modal = null; + } + }).toPromise(); + } } diff --git a/src/ng2-bs3-modal/modal/models.ts b/src/ng2-bs3-modal/modal/models.ts index 00b4a8e..1acba59 100644 --- a/src/ng2-bs3-modal/modal/models.ts +++ b/src/ng2-bs3-modal/modal/models.ts @@ -1,5 +1,5 @@ -export { BsModalCloseEvent } from './models/modal-close-event'; -export { BsModalCloseSource } from './models/modal-close-source'; +export { BsModalHideEvent } from './models/modal-hide-event'; +export { BsModalHideType } from './models/modal-hide-type'; export { BsModalOptions } from './models/modal-options'; export { BsModalSize } from './models/modal-size'; diff --git a/src/ng2-bs3-modal/modal/models/modal-close-event.ts b/src/ng2-bs3-modal/modal/models/modal-close-event.ts deleted file mode 100644 index de3adcf..0000000 --- a/src/ng2-bs3-modal/modal/models/modal-close-event.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { BsModalCloseSource } from './modal-close-source'; - -export interface BsModalCloseEvent { - event: Event; - type: BsModalCloseSource; -} - diff --git a/src/ng2-bs3-modal/modal/models/modal-close-source.ts b/src/ng2-bs3-modal/modal/models/modal-close-source.ts deleted file mode 100644 index 1643266..0000000 --- a/src/ng2-bs3-modal/modal/models/modal-close-source.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum BsModalCloseSource { - Confirm, - Dismiss, - Backdrop, - Keyboard -} diff --git a/src/ng2-bs3-modal/modal/models/modal-hide-event.ts b/src/ng2-bs3-modal/modal/models/modal-hide-event.ts new file mode 100644 index 0000000..e2bbd33 --- /dev/null +++ b/src/ng2-bs3-modal/modal/models/modal-hide-event.ts @@ -0,0 +1,7 @@ +import { BsModalHideType } from './modal-hide-type'; + +export interface BsModalHideEvent { + event: Event; + type: BsModalHideType; +} + diff --git a/src/ng2-bs3-modal/modal/models/modal-hide-type.ts b/src/ng2-bs3-modal/modal/models/modal-hide-type.ts new file mode 100644 index 0000000..80d40d8 --- /dev/null +++ b/src/ng2-bs3-modal/modal/models/modal-hide-type.ts @@ -0,0 +1,8 @@ +export enum BsModalHideType { + Close, + Dismiss, + Backdrop, + Keyboard, + RouteChange, + Destroy +} diff --git a/src/ng2-bs3-modal/ng2-bs3-modal.spec.ts b/src/ng2-bs3-modal/ng2-bs3-modal.spec.ts index 8c7630d..520836b 100644 --- a/src/ng2-bs3-modal/ng2-bs3-modal.spec.ts +++ b/src/ng2-bs3-modal/ng2-bs3-modal.spec.ts @@ -64,6 +64,7 @@ describe('ModalComponent', () => { modal.onClose.subscribe(spy); modal.open(); + tick(); modal.close(); tick(); @@ -86,25 +87,29 @@ describe('ModalComponent', () => { })); it('should emit onDismiss when modal is dimissed and animation is disabled', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; - const spy = jasmine.createSpy(''); + const spy = jasmine.createSpy('onDismiss'); + modal.onDismiss.subscribe(spy); + fixture.detectChanges(); + modal.open(); + tick(); modal.dismiss(); tick(); + expect(spy).toHaveBeenCalled(); })); it('should emit onDismiss when modal is dismissed and animation is enabled', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal: BsModalComponent = fixture.componentInstance.modal; const spy = jasmine.createSpy('onDismiss'); + modal.onDismiss.subscribe(spy); fixture.componentInstance.animate = true; fixture.detectChanges(); - modal.ngAfterViewInit(); - modal.onDismiss.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); @@ -116,13 +121,13 @@ describe('ModalComponent', () => { })); it('should emit onDismiss only once', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; const spy = jasmine.createSpy('onDismiss').and.callFake(() => { }); + modal.onDismiss.subscribe(spy); fixture.componentInstance.animate = true; fixture.detectChanges(); - modal.onDismiss.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); @@ -134,14 +139,14 @@ describe('ModalComponent', () => { })); it('should emit onDismiss only once when showDefaultButtons is false', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; const spy = jasmine.createSpy('onDismiss'); + modal.onDismiss.subscribe(spy); fixture.componentInstance.animate = true; fixture.componentInstance.defaultButtons = false; fixture.detectChanges(); - modal.onDismiss.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); @@ -153,13 +158,13 @@ describe('ModalComponent', () => { })); it('should emit onDismiss when modal is closed, opened, then dimissed from backdrop', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; const spy = jasmine.createSpy('onDismiss'); + modal.onDismiss.subscribe(spy); fixture.componentInstance.animate = true; fixture.detectChanges(); - modal.onDismiss.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); @@ -176,13 +181,13 @@ describe('ModalComponent', () => { })); it('should emit onDismiss when modal is dismissed a second time from backdrop', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; const spy = jasmine.createSpy('onDismiss'); + modal.onDismiss.subscribe(spy); fixture.componentInstance.animate = true; fixture.detectChanges(); - modal.onDismiss.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); @@ -199,14 +204,14 @@ describe('ModalComponent', () => { })); it('should emit onDismiss when modal is dismissed a second time from backdrop and showDefaultButtons is false', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; const spy = jasmine.createSpy('onDismiss'); + modal.onDismiss.subscribe(spy); fixture.componentInstance.animate = true; fixture.componentInstance.defaultButtons = false; fixture.detectChanges(); - modal.onDismiss.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); @@ -223,13 +228,13 @@ describe('ModalComponent', () => { })); it('should emit onOpen when modal is opened and animations have been enabled', fakeAsync(() => { - fixture = createRoot(TestComponent); + fixture = createRoot(TestComponent, null, false); const modal = fixture.componentInstance.modal; const spy = jasmine.createSpy('onOpenAnimated'); + modal.onOpen.subscribe(spy); fixture.componentInstance.animate = true; fixture.detectChanges(); - modal.onOpen.subscribe(spy); modal.open(); modal.triggerTransitionEnd(); diff --git a/src/ng2-bs3-modal/utils/to-event-emitter.ts b/src/ng2-bs3-modal/utils/to-event-emitter.ts deleted file mode 100644 index 13fc05a..0000000 --- a/src/ng2-bs3-modal/utils/to-event-emitter.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Observable } from 'rxjs/Observable'; -import { EventEmitter, NgZone } from '@angular/core'; - -Observable.prototype.toEventEmitter = toEventEmitter; - -export function toEventEmitter(this: Observable, zone: NgZone): EventEmitter { - const emitter = new EventEmitter(true); - this.subscribe((next) => { - zone.run(() => { - emitter.next(next); - }); - }); - return emitter; -} - -declare module 'rxjs/Observable' { - // tslint:disable-next-line:no-shadowed-variable - interface Observable { - toEventEmitter: typeof toEventEmitter; - } -} diff --git a/src/test/common.ts b/src/test/common.ts index 51b5229..67f4e86 100644 --- a/src/test/common.ts +++ b/src/test/common.ts @@ -2,9 +2,9 @@ import { Type, } from '@angular/core'; import { Router } from '@angular/router'; import { ComponentFixture, TestBed, tick } from '@angular/core/testing'; -export function createRoot(type: Type, router?: Router): ComponentFixture { +export function createRoot(type: Type, router?: Router, detect = true): ComponentFixture { const f = TestBed.createComponent(type); - f.detectChanges(); + if (detect) f.detectChanges(); if (router) { router.initialNavigation(); advance(f);