diff --git a/components/breadcrumb/nz-breadcrumb.component.ts b/components/breadcrumb/nz-breadcrumb.component.ts index 441d42cdc17..4c88f8ea98c 100755 --- a/components/breadcrumb/nz-breadcrumb.component.ts +++ b/components/breadcrumb/nz-breadcrumb.component.ts @@ -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'; diff --git a/components/message/nz-message-base.service.ts b/components/message/nz-message-base.service.ts new file mode 100644 index 00000000000..812de44b7b9 --- /dev/null +++ b/components/message/nz-message-base.service.ts @@ -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(); + +export class NzMessageBaseService< + ContainerClass extends NzMessageContainerComponent, + MessageData, + MessageConfig extends NzMessageConfig +> { + protected _container: ContainerClass; + + constructor( + private overlay: Overlay, + private containerClass: Type, + 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; + } +} diff --git a/components/message/nz-message.module.ts b/components/message/nz-message.module.ts index eacc5ca1ffb..e45ec13713d 100644 --- a/components/message/nz-message.module.ts +++ b/components/message/nz-message.module.ts @@ -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] diff --git a/components/message/nz-message.service.module.ts b/components/message/nz-message.service.module.ts new file mode 100644 index 00000000000..a1ef873d447 --- /dev/null +++ b/components/message/nz-message.service.module.ts @@ -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 {} diff --git a/components/message/nz-message.service.ts b/components/message/nz-message.service.ts index 06e5cf6f788..9fb1564b75f 100644 --- a/components/message/nz-message.service.ts +++ b/components/message/nz-message.service.ts @@ -7,87 +7,16 @@ */ 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, - 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, @@ -95,7 +24,7 @@ export class NzMessageService extends NzMessageBaseService< 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 diff --git a/components/message/nz-message.spec.ts b/components/message/nz-message.spec.ts index 1894fb90612..414a71ec1c2 100644 --- a/components/message/nz-message.spec.ts +++ b/components/message/nz-message.spec.ts @@ -11,7 +11,6 @@ import { NzMessageService } from './nz-message.service'; describe('NzMessage', () => { let messageService: NzMessageService; - let overlayContainer: OverlayContainer; let overlayContainerElement: HTMLElement; let fixture: ComponentFixture; let testComponent: NzTestMessageBasicComponent; @@ -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(() => { @@ -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'); @@ -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(); }); @@ -123,6 +123,9 @@ describe('NzMessage', () => { messageService.remove(filledMessage.messageId); fixture.detectChanges(); + filledMessage!.onClose!.subscribe(() => { + console.log(1); + }); expect(overlayContainerElement.textContent).not.toContain('SUCCESS'); })); @@ -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(() => { diff --git a/components/message/public-api.ts b/components/message/public-api.ts index 5cbe6de0bd1..11f50179dc0 100644 --- a/components/message/public-api.ts +++ b/components/message/public-api.ts @@ -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'; diff --git a/components/notification/nz-notification.module.ts b/components/notification/nz-notification.module.ts index 5435b48433a..f76ef58fc68 100644 --- a/components/notification/nz-notification.module.ts +++ b/components/notification/nz-notification.module.ts @@ -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] diff --git a/components/notification/nz-notification.service.module.ts b/components/notification/nz-notification.service.module.ts new file mode 100644 index 00000000000..ac54f554b3f --- /dev/null +++ b/components/notification/nz-notification.service.module.ts @@ -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 {} diff --git a/components/notification/nz-notification.service.ts b/components/notification/nz-notification.service.ts index bca7f2fd420..7054112694b 100644 --- a/components/notification/nz-notification.service.ts +++ b/components/notification/nz-notification.service.ts @@ -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, diff --git a/components/notification/nz-notification.spec.ts b/components/notification/nz-notification.spec.ts index d594a7e67ce..855f1ad621d 100644 --- a/components/notification/nz-notification.spec.ts +++ b/components/notification/nz-notification.spec.ts @@ -20,7 +20,6 @@ export class DemoAppComponent { describe('NzNotification', () => { let notificationService: NzNotificationService; - let overlayContainer: OverlayContainer; let overlayContainerElement: HTMLElement; let fixture: ComponentFixture; @@ -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(() => { diff --git a/components/notification/public-api.ts b/components/notification/public-api.ts index 07abaa98051..dbcfb67b6de 100644 --- a/components/notification/public-api.ts +++ b/components/notification/public-api.ts @@ -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'; diff --git a/components/typography/nz-typography.spec.ts b/components/typography/nz-typography.spec.ts index d9cd32d512e..7fea182fbff 100644 --- a/components/typography/nz-typography.spec.ts +++ b/components/typography/nz-typography.spec.ts @@ -295,7 +295,6 @@ describe('typography', () => { }); @Component({ - selector: 'nz-test-typography', template: `

h1. Ant Design

h2. Ant Design

@@ -317,7 +316,6 @@ describe('typography', () => { export class NzTestTypographyComponent {} @Component({ - selector: 'nz-test-typography-copy', template: `

@@ -332,7 +330,6 @@ export class NzTestTypographyCopyComponent { } @Component({ - selector: 'nz-test-typography-edit', template: `

`