Skip to content

Commit

Permalink
fix(module:message): fix lazy load problem (#3797)
Browse files Browse the repository at this point in the history
* fix(module:message): fix lazy load problem

close #3794

* test(module:message): fix test

* fix(module:message): fix module
  • Loading branch information
hsuanxyz authored and Wendell committed Jul 16, 2019
1 parent 4dd93e6 commit 679fdea
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 99 deletions.
2 changes: 1 addition & 1 deletion components/breadcrumb/nz-breadcrumb.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '@angular/core';
import { ActivatedRoute, NavigationEnd, Params, PRIMARY_OUTLET, Router } from '@angular/router';
import { Subject } from 'rxjs';
import { filter, takeUntil, startWith } from 'rxjs/operators';
import { filter, startWith, takeUntil } from 'rxjs/operators';

import { InputBoolean, PREFIX } from 'ng-zorro-antd/core';

Expand Down
84 changes: 84 additions & 0 deletions components/message/nz-message-base.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { Overlay } from '@angular/cdk/overlay';
import { ApplicationRef, ComponentFactoryResolver, EmbeddedViewRef, Injector, Type } from '@angular/core';

import { NzMessageConfig } from './nz-message-config';
import { NzMessageContainerComponent } from './nz-message-container.component';
import { NzMessageData, NzMessageDataFilled, NzMessageDataOptions } from './nz-message.definitions';

let globalCounter = 0;
const containerMap = new Map<string, NzMessageContainerComponent>();

export class NzMessageBaseService<
ContainerClass extends NzMessageContainerComponent,
MessageData,
MessageConfig extends NzMessageConfig
> {
protected _container: ContainerClass;

constructor(
private overlay: Overlay,
private containerClass: Type<ContainerClass>,
private injector: Injector,
private cfr: ComponentFactoryResolver,
private appRef: ApplicationRef,
private name: string = ''
) {
this._container = this.createContainer();
containerMap.set(this.name, this._container);
}

remove(messageId?: string): void {
if (messageId) {
this._container.removeMessage(messageId);
} else {
this._container.removeMessageAll();
}
}

createMessage(message: MessageData, options?: NzMessageDataOptions): NzMessageDataFilled {
const resultMessage: NzMessageDataFilled = {
...(message as NzMessageData),
...{
createdAt: new Date(),
messageId: this._generateMessageId(),
options
}
};
this._container.createMessage(resultMessage);

return resultMessage;
}

config(config: MessageConfig): void {
this._container.setConfig(config);
}

protected _generateMessageId(): string {
return `${this.name}-${globalCounter++}`;
}

// Manually creating container for overlay to avoid multi-checking error, see: https://github.com/NG-ZORRO/ng-zorro-antd/issues/391
// NOTE: we never clean up the container component and it's overlay resources, if we should, we need to do it by our own codes.
private createContainer(): ContainerClass {
if (containerMap.has(this.name)) {
return containerMap.get(this.name) as ContainerClass;
}
const factory = this.cfr.resolveComponentFactory(this.containerClass);
const componentRef = factory.create(this.injector); // Use root injector
componentRef.changeDetectorRef.detectChanges(); // Immediately change detection to avoid multi-checking error
this.appRef.attachView(componentRef.hostView); // Load view into app root
const overlayPane = this.overlay.create().overlayElement;
overlayPane.style.zIndex = '1010'; // Patching: assign the same zIndex of ant-message to it's parent overlay panel, to the ant-message's zindex work.
overlayPane.appendChild((componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);

return componentRef.instance;
}
}
3 changes: 2 additions & 1 deletion components/message/nz-message.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { NzIconModule } from 'ng-zorro-antd/icon';
import { NZ_MESSAGE_DEFAULT_CONFIG_PROVIDER } from './nz-message-config';
import { NzMessageContainerComponent } from './nz-message-container.component';
import { NzMessageComponent } from './nz-message.component';
import { NzMessageServiceModule } from './nz-message.service.module';

@NgModule({
imports: [CommonModule, OverlayModule, NzIconModule, NzAddOnModule],
imports: [CommonModule, OverlayModule, NzIconModule, NzAddOnModule, NzMessageServiceModule],
declarations: [NzMessageContainerComponent, NzMessageComponent],
providers: [NZ_MESSAGE_DEFAULT_CONFIG_PROVIDER],
entryComponents: [NzMessageContainerComponent]
Expand Down
12 changes: 12 additions & 0 deletions components/message/nz-message.service.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { NgModule } from '@angular/core';

@NgModule()
export class NzMessageServiceModule {}
81 changes: 5 additions & 76 deletions components/message/nz-message.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,95 +7,24 @@
*/

import { Overlay } from '@angular/cdk/overlay';
import {
ApplicationRef,
ComponentFactoryResolver,
EmbeddedViewRef,
Injectable,
Injector,
TemplateRef,
Type
} from '@angular/core';
import { ApplicationRef, ComponentFactoryResolver, Injectable, Injector, TemplateRef } from '@angular/core';

import { NzMessageBaseService } from './nz-message-base.service';
import { NzMessageConfig } from './nz-message-config';
import { NzMessageContainerComponent } from './nz-message-container.component';
import { NzMessageData, NzMessageDataFilled, NzMessageDataOptions } from './nz-message.definitions';

let globalCounter = 0;

export class NzMessageBaseService<
ContainerClass extends NzMessageContainerComponent,
MessageData,
MessageConfig extends NzMessageConfig
> {
protected _container: ContainerClass;

constructor(
private overlay: Overlay,
private containerClass: Type<ContainerClass>,
private injector: Injector,
private cfr: ComponentFactoryResolver,
private appRef: ApplicationRef,
private _idPrefix: string = ''
) {
this._container = this.createContainer();
}

remove(messageId?: string): void {
if (messageId) {
this._container.removeMessage(messageId);
} else {
this._container.removeMessageAll();
}
}

createMessage(message: MessageData, options?: NzMessageDataOptions): NzMessageDataFilled {
const resultMessage: NzMessageDataFilled = {
...(message as NzMessageData),
...{
createdAt: new Date(),
messageId: this._generateMessageId(),
options
}
};
this._container.createMessage(resultMessage);

return resultMessage;
}

config(config: MessageConfig): void {
this._container.setConfig(config);
}

protected _generateMessageId(): string {
return this._idPrefix + globalCounter++;
}

// Manually creating container for overlay to avoid multi-checking error, see: https://github.com/NG-ZORRO/ng-zorro-antd/issues/391
// NOTE: we never clean up the container component and it's overlay resources, if we should, we need to do it by our own codes.
private createContainer(): ContainerClass {
const factory = this.cfr.resolveComponentFactory(this.containerClass);
const componentRef = factory.create(this.injector); // Use root injector
componentRef.changeDetectorRef.detectChanges(); // Immediately change detection to avoid multi-checking error
this.appRef.attachView(componentRef.hostView); // Load view into app root
const overlayPane = this.overlay.create().overlayElement;
overlayPane.style.zIndex = '1010'; // Patching: assign the same zIndex of ant-message to it's parent overlay panel, to the ant-message's zindex work.
overlayPane.appendChild((componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);

return componentRef.instance;
}
}
import { NzMessageServiceModule } from './nz-message.service.module';

@Injectable({
providedIn: 'root'
providedIn: NzMessageServiceModule
})
export class NzMessageService extends NzMessageBaseService<
NzMessageContainerComponent,
NzMessageData,
NzMessageConfig
> {
constructor(overlay: Overlay, injector: Injector, cfr: ComponentFactoryResolver, appRef: ApplicationRef) {
super(overlay, NzMessageContainerComponent, injector, cfr, appRef, 'message-');
super(overlay, NzMessageContainerComponent, injector, cfr, appRef, 'message');
}

// Shortcut methods
Expand Down
28 changes: 16 additions & 12 deletions components/message/nz-message.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { NzMessageService } from './nz-message.service';

describe('NzMessage', () => {
let messageService: NzMessageService;
let overlayContainer: OverlayContainer;
let overlayContainerElement: HTMLElement;
let fixture: ComponentFixture<NzTestMessageBasicComponent>;
let testComponent: NzTestMessageBasicComponent;
Expand All @@ -28,12 +27,13 @@ describe('NzMessage', () => {

beforeEach(inject([NzMessageService, OverlayContainer], (m: NzMessageService, oc: OverlayContainer) => {
messageService = m;
overlayContainer = oc;
overlayContainerElement = oc.getContainerElement();
if (!overlayContainerElement) {
overlayContainerElement = oc.getContainerElement();
}
}));

afterEach(() => {
overlayContainer.ngOnDestroy();
messageService.remove();
});

beforeEach(() => {
Expand All @@ -44,6 +44,7 @@ describe('NzMessage', () => {
it('should open a message box with success', () => {
messageService.success('SUCCESS');
fixture.detectChanges();
console.log(overlayContainerElement.textContent);

expect((overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement).style.zIndex).toBe('1010');
expect(overlayContainerElement.textContent).toContain('SUCCESS');
Expand All @@ -53,7 +54,6 @@ describe('NzMessage', () => {
it('should open a message box with error', () => {
messageService.error('ERROR');
fixture.detectChanges();

expect(overlayContainerElement.textContent).toContain('ERROR');
expect(overlayContainerElement.querySelector('.anticon-close-circle')).not.toBeNull();
});
Expand Down Expand Up @@ -123,6 +123,9 @@ describe('NzMessage', () => {

messageService.remove(filledMessage.messageId);
fixture.detectChanges();
filledMessage!.onClose!.subscribe(() => {
console.log(1);
});
expect(overlayContainerElement.textContent).not.toContain('SUCCESS');
}));

Expand Down Expand Up @@ -163,15 +166,16 @@ describe('NzMessage', () => {
}));

it('should emit event when message close', fakeAsync(() => {
let onCloseFlag = false;
messageService.config({ nzDuration: 2000 });
const closeSpy = jasmine.createSpy('message closed');
const msg = messageService.create('loading', 'CLOSE');
msg.onClose!.subscribe(() => {
onCloseFlag = true;
});

const messageId = msg.messageId;
msg.onClose!.subscribe(closeSpy);
fixture.detectChanges();
tick(50000);
expect(onCloseFlag).toBeTruthy();
messageService.remove(messageId);
tick(2000);
fixture.detectChanges();
expect(closeSpy).toHaveBeenCalledTimes(1);
}));

it('should container top to configured', fakeAsync(() => {
Expand Down
2 changes: 2 additions & 0 deletions components/message/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

export * from './nz-message-base.service';
export * from './nz-message.service';
export * from './nz-message.service.module';
export * from './nz-message.module';
export * from './nz-message.component';
export * from './nz-message.definitions';
Expand Down
3 changes: 2 additions & 1 deletion components/notification/nz-notification.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import { NzIconModule } from 'ng-zorro-antd/icon';
import { NZ_NOTIFICATION_DEFAULT_CONFIG_PROVIDER } from './nz-notification-config';
import { NzNotificationContainerComponent } from './nz-notification-container.component';
import { NzNotificationComponent } from './nz-notification.component';
import { NzNotificationServiceModule } from './nz-notification.service.module';

@NgModule({
imports: [CommonModule, OverlayModule, NzIconModule],
imports: [CommonModule, OverlayModule, NzIconModule, NzNotificationServiceModule],
declarations: [NzNotificationComponent, NzNotificationContainerComponent],
providers: [NZ_NOTIFICATION_DEFAULT_CONFIG_PROVIDER],
entryComponents: [NzNotificationContainerComponent]
Expand Down
12 changes: 12 additions & 0 deletions components/notification/nz-notification.service.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* @license
* Copyright Alibaba.com All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
*/

import { NgModule } from '@angular/core';

@NgModule()
export class NzNotificationServiceModule {}
3 changes: 2 additions & 1 deletion components/notification/nz-notification.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import { NzMessageBaseService } from 'ng-zorro-antd/message';
import { NzNotificationConfig } from './nz-notification-config';
import { NzNotificationContainerComponent } from './nz-notification-container.component';
import { NzNotificationData, NzNotificationDataFilled, NzNotificationDataOptions } from './nz-notification.definitions';
import { NzNotificationServiceModule } from './nz-notification.service.module';

@Injectable({
providedIn: 'root'
providedIn: NzNotificationServiceModule
})
export class NzNotificationService extends NzMessageBaseService<
NzNotificationContainerComponent,
Expand Down
8 changes: 4 additions & 4 deletions components/notification/nz-notification.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export class DemoAppComponent {

describe('NzNotification', () => {
let notificationService: NzNotificationService;
let overlayContainer: OverlayContainer;
let overlayContainerElement: HTMLElement;
let fixture: ComponentFixture<DemoAppComponent>;

Expand All @@ -36,12 +35,13 @@ describe('NzNotification', () => {

beforeEach(inject([NzNotificationService, OverlayContainer], (n: NzNotificationService, oc: OverlayContainer) => {
notificationService = n;
overlayContainer = oc;
overlayContainerElement = oc.getContainerElement();
if (!overlayContainerElement) {
overlayContainerElement = oc.getContainerElement();
}
}));

afterEach(() => {
overlayContainer.ngOnDestroy();
notificationService.remove();
});

beforeEach(() => {
Expand Down
1 change: 1 addition & 0 deletions components/notification/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export * from './nz-notification.component';
export * from './nz-notification.module';
export * from './nz-notification.definitions';
export * from './nz-notification.service';
export * from './nz-notification.service.module';
export * from './nz-notification-container.component';
3 changes: 0 additions & 3 deletions components/typography/nz-typography.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ describe('typography', () => {
});

@Component({
selector: 'nz-test-typography',
template: `
<h1 nz-title>h1. Ant Design</h1>
<h2 nz-title>h2. Ant Design</h2>
Expand All @@ -317,7 +316,6 @@ describe('typography', () => {
export class NzTestTypographyComponent {}

@Component({
selector: 'nz-test-typography-copy',
template: `
<h4 nz-title nzCopyable class="test-copy-h4" nzContent="Ant Design-0" (nzCopy)="onCopy($event)"></h4>
<p nz-paragraph nzCopyable class="test-copy-p" nzContent="Ant Design-1" (nzCopy)="onCopy($event)"></p>
Expand All @@ -332,7 +330,6 @@ export class NzTestTypographyCopyComponent {
}

@Component({
selector: 'nz-test-typography-edit',
template: `
<p nz-paragraph nzEditable (nzContentChange)="onChange($event)" [nzContent]="str"></p>
`
Expand Down

0 comments on commit 679fdea

Please sign in to comment.