Skip to content

Commit

Permalink
fix(module:modal): close modal itself before destructing by the angul…
Browse files Browse the repository at this point in the history
…ar's lifecycle (#1769)

close #1663
  • Loading branch information
wilsoncook authored and wen committed Aug 31, 2018
1 parent cb34983 commit 075c7a4
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 15 deletions.
2 changes: 2 additions & 0 deletions components/modal/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ The dialog is currently divided into 2 modes, `normal mode` and `confirm box mod

> The default state of `<nz-modal>` will not be automatically cleared. If you wish to open new content each time, use the `NzModalService` service to create modals (when created as a service, the `nzAfterClose` event will be listened by default aim to destroy the modal).
> Modals created through the `NzModalService` service need you to manage their own life cycle. For example, when you switch the page route, the modal box created by service will not be destroyed automatically. You need to use the modal box's reference to manually destroy it (`NzModalRef.close()` or `NzModalRef.destroy()`).
#### Using service to create Normal Mode modal

> You can call `NzModalService.create(options)` to dynamically create **normal mode** modals, where `options` is an object that supports the support given in the API above **normal mode** parameters
Expand Down
2 changes: 2 additions & 0 deletions components/modal/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ title: Modal

> `<nz-modal>` 默认关闭后状态不会自动清空, 如果希望每次打开都是新内容,请采用 `NzModalService` 服务方式创建对话框(当以服务方式创建时,默认会监听 `nzAfterClose` 并销毁对话框)。
> 通过 `NzModalService` 服务方式创建的对话框需要自行管理其生命周期。比如你在页面路由切换时,服务方式创建的对话框并不会被销毁,你需要使用对话框引用来手动销毁(`NzModalRef.close()``NzModalRef.destroy()`)。
#### 采用服务方式创建普通模式对话框

> 您可调用 `NzModalService.create(options)` 来动态创建**普通模式**对话框,这里的 `options` 是一个对象,支持上方API中给出的支持 **普通模式** 的参数
Expand Down
13 changes: 11 additions & 2 deletions components/modal/nz-modal-control.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,17 @@ export class NzModalControlService {
}
}

// TODO: allow deregister modals
// deregisterModal(modalRef: NzModalRef): void {}
// deregister modals
deregisterModal(modalRef: NzModalRef): void {
const registeredMeta = this.registeredMetaMap.get(modalRef);
if (registeredMeta) {
// Remove this modal if it is still in the opened modal list (NOTE: it may trigger "afterAllClose")
this.removeOpenModal(registeredMeta.modalRef);
registeredMeta.afterOpenSubscription.unsubscribe();
registeredMeta.afterCloseSubscription.unsubscribe();
this.registeredMetaMap.delete(modalRef);
}
}

hasRegistered(modalRef: NzModalRef): boolean {
return this.registeredMetaMap.has(modalRef);
Expand Down
16 changes: 11 additions & 5 deletions components/modal/nz-modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,17 @@ export class NzModalComponent<T = any, R = any> extends NzModalRef<T, R> impleme
}

ngOnDestroy(): void {
if (this.container instanceof OverlayRef) {
this.container.dispose();
}
this.unsubscribe$.next();
this.unsubscribe$.complete();
// Close self before destructing
this.changeVisibleFromInside(false).then(() => {
this.modalControl.deregisterModal(this);

if (this.container instanceof OverlayRef) {
this.container.dispose();
}

this.unsubscribe$.next();
this.unsubscribe$.complete();
});
}

open(): void {
Expand Down
65 changes: 57 additions & 8 deletions components/modal/nz-modal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Component, ElementRef, EventEmitter, Input } from '@angular/core';
import { async, fakeAsync, flush, inject, tick, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

import { OverlayContainer } from '@angular/cdk/overlay';
import { NzButtonComponent } from '../button/nz-button.component';
Expand All @@ -29,7 +30,7 @@ describe('modal testing (legacy)', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ NzButtonModule, NzModalModule ],
imports: [ NoopAnimationsModule, NzButtonModule, NzModalModule ],
declarations: [ NzDemoModalAsyncComponent ],
providers : [ NzMeasureScrollbarService ]
}).compileComponents();
Expand Down Expand Up @@ -68,7 +69,7 @@ describe('modal testing (legacy)', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ NzButtonModule, NzModalModule ],
imports: [ NoopAnimationsModule, NzButtonModule, NzModalModule ],
declarations: [ NzDemoModalConfirmPromiseComponent ],
providers : [ NzMeasureScrollbarService ]
}).compileComponents();
Expand Down Expand Up @@ -115,7 +116,7 @@ describe('modal testing (legacy)', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ NzModalModule ],
imports: [ NoopAnimationsModule, NzModalModule ],
declarations: [ TestBasicServiceComponent ],
providers : [ NzMeasureScrollbarService ]
}).compileComponents();
Expand Down Expand Up @@ -186,7 +187,7 @@ describe('modal testing (legacy)', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ NzModalModule ],
imports: [ NoopAnimationsModule, NzModalModule ],
declarations: [ TestVaryServiceComponent, TestVaryServiceCustomComponent ],
providers : [ NzMeasureScrollbarService ]
});
Expand Down Expand Up @@ -234,7 +235,7 @@ describe('modal testing (legacy)', () => {
describe('ConfirmModal: should apply options correctly', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ NzModalModule ],
imports: [ NoopAnimationsModule, NzModalModule ],
declarations: [ TestConfirmModalComponent ],
providers : [ NzMeasureScrollbarService ]
}).compileComponents();
Expand Down Expand Up @@ -278,6 +279,7 @@ describe('modal testing (legacy)', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ NoopAnimationsModule ],
declarations: [ CssUnitPipe, TestCssUnitPipeComponent ]
}).compileComponents();
}));
Expand All @@ -302,7 +304,7 @@ describe('modal testing (legacy)', () => {

it('#i18n', () => {
const injector = TestBed.configureTestingModule({
imports: [ NzButtonModule, NzModalModule ],
imports: [ NoopAnimationsModule, NzButtonModule, NzModalModule ],
declarations: [ NzDemoModalAsyncComponent ],
providers : [ NzMeasureScrollbarService ]
});
Expand All @@ -326,9 +328,10 @@ describe('NzModal', () => {

beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({
imports: [ NzModalModule ],
providers : [ NzMeasureScrollbarService ],
imports: [ NoopAnimationsModule, NzModalModule ],
providers: [ NzMeasureScrollbarService ],
declarations: [
NzDemoModalBasicComponent,
ModalByServiceComponent
]
});
Expand All @@ -346,6 +349,25 @@ describe('NzModal', () => {
overlayContainer.ngOnDestroy();
});

describe('basic usage', () => {
let fixture: ComponentFixture<NzDemoModalBasicComponent>;
beforeEach(() => {
fixture = TestBed.createComponent(NzDemoModalBasicComponent);
});

it('should destroy normally when the component context is over', fakeAsync(() => {
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
expect(overlayContainerElement.textContent).toContain('BASIC_MODAL_TITLE');
fixture.componentInstance.modalAvailable = false;
fixture.detectChanges();
tick(1000);
fixture.detectChanges();
expect(overlayContainerElement.textContent).not.toContain('BASIC_MODAL_TITLE');
}));
});

describe('created by service', () => {
let fixture: ComponentFixture<ModalByServiceComponent>;

Expand Down Expand Up @@ -455,6 +477,22 @@ describe('NzModal', () => {
expect(modalService.openModals.length).toBe(1);
}));

it('should degregister a modal', fakeAsync(() => {
const modalRef = modalService.create();
const modalControl = (modalService as any).modalControl as NzModalControlService; // tslint:disable-line:no-any

fixture.detectChanges();
tick(600);
expect(modalService.openModals.length).toBe(1);

modalControl.deregisterModal(modalRef);
expect(modalService.openModals.length).toBe(0);

// Should nothing happened
modalControl.deregisterModal(modalRef);
expect(modalService.openModals.length).toBe(0);
}));

it('should trigger nzOnOk/nzOnCancel', () => {
const spyOk = jasmine.createSpy('ok spy');
const spyCancel = jasmine.createSpy('cancel spy');
Expand Down Expand Up @@ -496,6 +534,17 @@ describe('NzModal', () => {
// | Testing Components
// -------------------------------------------

@Component({
template: `
<nz-modal *ngIf="modalAvailable" nzVisible nzTitle="BASIC_MODAL_TITLE">
<p>content</p>
</nz-modal>
`
})
class NzDemoModalBasicComponent {
modalAvailable = true;
}

@Component({
selector: 'nz-demo-modal-async',
template: `
Expand Down

0 comments on commit 075c7a4

Please sign in to comment.