Skip to content

Commit

Permalink
chore(module:empty): refactor (NG-ZORRO#4726)
Browse files Browse the repository at this point in the history
* chore(module:empty): refactor

feat(module:empty): add no description feature

refactor(module:empty): remove empty service

fix(module:empty): fix spec

fix: fix spec import path

* fix: fix empty content detection is triggered too late

* test: skip falsy value test

* chore: remove redundant type check
  • Loading branch information
Wendell authored Feb 12, 2020
1 parent 6d2a80e commit 048902e
Show file tree
Hide file tree
Showing 22 changed files with 342 additions and 275 deletions.
6 changes: 4 additions & 2 deletions components/core/testing/componet-bed.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { CommonModule } from '@angular/common';
import { DebugElement, NO_ERRORS_SCHEMA, Provider, Type } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed, TestBedStatic } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { NzSafeAny } from 'ng-zorro-antd/core/types';

type ComponentDeps = Array<Type<NzSafeAny>>;
export interface ComponentBed<T> {
bed: TestBedStatic;
fixture: ComponentFixture<T>;
nativeElement: HTMLElement;
debugElement: DebugElement;
Expand All @@ -30,10 +31,11 @@ export function createComponentBed<T>(
schemas: [NO_ERRORS_SCHEMA],
providers: providers || []
};
TestBed.configureTestingModule(config);
const bed = TestBed.configureTestingModule(config);
const fixture = TestBed.createComponent<T>(component);
fixture.detectChanges();
return {
bed,
fixture,
nativeElement: fixture.nativeElement,
debugElement: fixture.debugElement,
Expand Down
24 changes: 24 additions & 0 deletions components/empty/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @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
*/

/**
* @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 { InjectionToken, TemplateRef, Type } from '@angular/core';

export type NzEmptySize = 'normal' | 'small' | '';

// tslint:disable-next-line:no-any
export type NzEmptyCustomContent = Type<any> | TemplateRef<any> | string;

export const NZ_EMPTY_COMPONENT_NAME = new InjectionToken<string>('nz-empty-component-name');
2 changes: 1 addition & 1 deletion components/empty/demo/config.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 2
order: 3
title:
zh-CN: 全局化配置
en-US: Default Config
Expand Down
2 changes: 1 addition & 1 deletion components/empty/demo/customize.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 1
order: 2
title:
zh-CN: 自定义
en-US: Customize
Expand Down
14 changes: 14 additions & 0 deletions components/empty/demo/description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 4
title:
zh-CN: 无描述
en-US: No description
---

## zh-CN

无描述展示。

## en-US

Simplest Usage with no description.
9 changes: 9 additions & 0 deletions components/empty/demo/description.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-empty-description',
template: `
<nz-empty [nzNotFoundContent]="null"></nz-empty>
`
})
export class NzDemoEmptyDescriptionComponent {}
14 changes: 14 additions & 0 deletions components/empty/demo/simple.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 1
title:
zh-CN: 选择图片
en-US: Chose image
---

## zh-CN

可以通过设置 `nzNotFoundImage``simple` 选择另一种风格的图片。

## en-US

You can choose another style of `image` by setting `simple` to `nzNotFoundImage`.
9 changes: 9 additions & 0 deletions components/empty/demo/simple.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-empty-simple',
template: `
<nz-empty nzNotFoundImage="simple"></nz-empty>
`
})
export class NzDemoEmptySimpleComponent {}
17 changes: 13 additions & 4 deletions components/empty/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import { NzEmptyModule } from 'ng-zorro-antd/empty';

| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| `[nzNotFoundImage]` | Customize image. Will tread as image url when string provided | `string` \| `TemplateRef<void>` | - |
| `[nzNotFoundContent]` | Custom description | `string` \| `TemplateRef<void>` | - |
| `[nzNotFoundFooter]` | Custom Footer | `string` \| `TemplateRef<void>` | - |
| `[nzNotFoundImage]` | Customize image. Will tread as image url when string provided | `string \| TemplateRef<void>` | - |
| `[nzNotFoundContent]` | Custom description | `string \| TemplateRef<void> \| null` | - |
| `[nzNotFoundFooter]` | Custom Footer | `string \| TemplateRef<void>` | - |

### `NZ_CONFIG`

Expand All @@ -37,10 +37,19 @@ The `nzEmpty` interface has properties as follows:

| Token | Description | Parameters |
| ----- | --- | ---- |
| `NZ_DEFAULT_EMPTY_CONTENT` | To provide a user default empty component | `Component` \| `string` |
| `NZ_EMPTY_COMPONENT_NAME` | Would be injected to `NZ_DEFAULT_EMPTY_CONTENT`, telling that component its parent component's name | `string` |

### Global Customizable Empty Content

You may notice or used some inputs like `nzNotFoundContent` in some components. Now they would use `Empty` component. So you can provide `nzDefaultEmptyContent` to customize them.

```ts
{
provide: NZ_CONFIG,
useValue: {
empty: {
nzDefaultEmptyContent
}
}
}
```
8 changes: 4 additions & 4 deletions components/empty/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import { NzEmptyModule } from 'ng-zorro-antd/empty';

| 参数 | 说明 | 类型 | 默认值 |
| -------- | ----------- | ---- | ------- |
| `[nzNotFoundImage]` | 设置显示图片,为 `string` 时表示自定义图片地址 | `string` \| `TemplateRef<void>` | - |
| `[nzNotFoundContent]` | 自定义描述内容 | `string` \| `TemplateRef<void>` | - |
| `[nzNotFoundFooter]` | 设置自定义 footer | `string` \| `TemplateRef<void>` | - |
| `[nzNotFoundImage]` | 设置显示图片,为 `string` 时表示自定义图片地址 | `string \| TemplateRef<void>` | - |
| `[nzNotFoundContent]` | 自定义描述内容 | `string \| TemplateRef<void> \| null` | - |
| `[nzNotFoundFooter]` | 设置自定义 footer | `string \| TemplateRef<void>` | - |

### `NZ_CONFIG`

Expand All @@ -42,5 +42,5 @@ import { NzEmptyModule } from 'ng-zorro-antd/empty';

### 全局自定义空组件

你或许知道或者用过一些类似 `nzNotFoundContent` 的属性来自定义组件数据为空时的内容,现在它们都会使用 `Empty` 组件。你可以通过在 `NZ_CONFIG` 中提供 `{ nzEmpty: { nzDefaultEmptyContent } }` 来定义一个自定义的全局空组件。
你或许知道或者用过一些类似 `nzNotFoundContent` 的属性来自定义组件数据为空时的内容,现在它们都会使用 `Empty` 组件。你可以通过在 `NZ_CONFIG` 中提供 `{ empty: { nzDefaultEmptyContent: something } }` 来定义一个自定义的全局空组件。

Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,11 @@ import {
ViewContainerRef,
ViewEncapsulation
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { startWith, takeUntil } from 'rxjs/operators';

import { NZ_EMPTY_COMPONENT_NAME, NzEmptyCustomContent, NzEmptySize, simpleEmptyImage } from './nz-empty-config';
import { NzEmptyService } from './nz-empty.service';
import { NzConfigService } from 'ng-zorro-antd/core';
import { NZ_EMPTY_COMPONENT_NAME, NzEmptyCustomContent, NzEmptySize } from './config';

function getEmptySize(componentName: string): NzEmptySize {
switch (componentName) {
Expand All @@ -51,7 +50,19 @@ type NzEmptyContentType = 'component' | 'template' | 'string';
encapsulation: ViewEncapsulation.None,
selector: 'nz-embed-empty',
exportAs: 'nzEmbedEmpty',
templateUrl: './nz-embed-empty.component.html'
template: `
<ng-container *ngIf="!content && specificContent !== null" [ngSwitch]="size">
<nz-empty *ngSwitchCase="'normal'" class="ant-empty-normal" [nzNotFoundImage]="'simple'"></nz-empty>
<nz-empty *ngSwitchCase="'small'" class="ant-empty-small" [nzNotFoundImage]="'simple'"></nz-empty>
<nz-empty *ngSwitchDefault></nz-empty>
</ng-container>
<ng-container *ngIf="content">
<ng-template *ngIf="contentType !== 'string'" [cdkPortalOutlet]="contentPortal"></ng-template>
<ng-container *ngIf="contentType === 'string'">
{{ content }}
</ng-container>
</ng-container>
`
})
export class NzEmbedEmptyComponent implements OnChanges, OnInit, OnDestroy {
@Input() nzComponentName: string;
Expand All @@ -60,14 +71,12 @@ export class NzEmbedEmptyComponent implements OnChanges, OnInit, OnDestroy {
content?: NzEmptyCustomContent;
contentType: NzEmptyContentType = 'string';
contentPortal?: Portal<any>; // tslint:disable-line:no-any
defaultSvg = this.sanitizer.bypassSecurityTrustResourceUrl(simpleEmptyImage);
size: NzEmptySize = '';

private $destroy = new Subject<void>();
private destroy$ = new Subject<void>();

constructor(
public emptyService: NzEmptyService,
private sanitizer: DomSanitizer,
private configService: NzConfigService,
private viewContainerRef: ViewContainerRef,
private cdr: ChangeDetectorRef,
private injector: Injector
Expand All @@ -85,15 +94,12 @@ export class NzEmbedEmptyComponent implements OnChanges, OnInit, OnDestroy {
}

ngOnInit(): void {
this.emptyService.userDefaultContent$.pipe(takeUntil(this.$destroy)).subscribe(content => {
this.content = this.specificContent || content;
this.renderEmpty();
});
this.subscribeDefaultEmptyContentChange();
}

ngOnDestroy(): void {
this.$destroy.next();
this.$destroy.complete();
this.destroy$.next();
this.destroy$.complete();
}

private renderEmpty(): void {
Expand All @@ -115,6 +121,21 @@ export class NzEmbedEmptyComponent implements OnChanges, OnInit, OnDestroy {
this.contentPortal = undefined;
}

this.cdr.markForCheck();
this.cdr.detectChanges();
}

private subscribeDefaultEmptyContentChange(): void {
this.configService
.getConfigChangeEventForComponent('empty')
.pipe(startWith(true), takeUntil(this.destroy$))
.subscribe(() => {
this.content = this.specificContent || this.getUserDefaultEmptyContent();
this.renderEmpty();
});
}

// tslint:disable-next-line:no-any
private getUserDefaultEmptyContent(): Type<any> | TemplateRef<string> | string | undefined {
return (this.configService.getConfigForComponent('empty') || {}).nzDefaultEmptyContent;
}
}
98 changes: 98 additions & 0 deletions components/empty/empty.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* @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 {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
TemplateRef,
ViewEncapsulation
} from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { NzI18nService } from 'ng-zorro-antd/i18n';

const NzEmptyDefaultImages = ['default', 'simple'] as const;
type NzEmptyNotFoundImageType = typeof NzEmptyDefaultImages[number] | null | string | TemplateRef<void>;

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
selector: 'nz-empty',
exportAs: 'nzEmpty',
styles: ['nz-empty { display: block; }'],
template: `
<div class="ant-empty-image">
<ng-container *ngIf="!isImageBuildIn">
<ng-container *nzStringTemplateOutlet="nzNotFoundImage">
<img [src]="nzNotFoundImage" [alt]="isContentString ? nzNotFoundContent : 'empty'" />
</ng-container>
</ng-container>
<nz-empty-default *ngIf="isImageBuildIn && nzNotFoundImage !== 'simple'"></nz-empty-default>
<nz-empty-simple *ngIf="isImageBuildIn && nzNotFoundImage === 'simple'"></nz-empty-simple>
</div>
<p class="ant-empty-description" *ngIf="nzNotFoundContent !== null">
<ng-container *nzStringTemplateOutlet="nzNotFoundContent">
{{ isContentString ? nzNotFoundContent : locale['description'] }}
</ng-container>
</p>
<div class="ant-empty-footer" *ngIf="nzNotFoundFooter">
<ng-container *nzStringTemplateOutlet="nzNotFoundFooter">
{{ nzNotFoundFooter }}
</ng-container>
</div>
`,
host: {
class: 'ant-empty'
}
})
export class NzEmptyComponent implements OnChanges, OnInit, OnDestroy {
@Input() nzNotFoundImage: NzEmptyNotFoundImageType = 'default';
@Input() nzNotFoundContent: string | TemplateRef<void> | null;
@Input() nzNotFoundFooter: string | TemplateRef<void>;

isContentString = false;
isImageBuildIn = true;
locale: { [key: string]: string } = {};

private readonly destroy$ = new Subject<void>();

constructor(private i18n: NzI18nService, private cdr: ChangeDetectorRef) {}

ngOnChanges(changes: SimpleChanges): void {
const { nzNotFoundContent, nzNotFoundImage } = changes;

if (nzNotFoundContent) {
const content = nzNotFoundContent.currentValue;
this.isContentString = typeof content === 'string';
}

if (nzNotFoundImage) {
const image = nzNotFoundImage.currentValue || 'default';
this.isImageBuildIn = NzEmptyDefaultImages.findIndex(i => i === image) > -1;
}
}

ngOnInit(): void {
this.i18n.localeChange.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.locale = this.i18n.getLocaleData('Empty');
this.cdr.markForCheck();
});
}

ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import { NzOutletModule } from 'ng-zorro-antd/core';

import { NzI18nModule } from 'ng-zorro-antd/i18n';

import { NzEmbedEmptyComponent } from './nz-embed-empty.component';
import { NzEmptyComponent } from './nz-empty.component';
import { NzEmbedEmptyComponent } from './embed-empty.component';
import { NzEmptyComponent } from './empty.component';
import { NzEmptyDefaultComponent } from './partial/default';
import { NzEmptySimpleComponent } from './partial/simple';

@NgModule({
imports: [CommonModule, PortalModule, NzOutletModule, NzI18nModule],
declarations: [NzEmptyComponent, NzEmbedEmptyComponent],
declarations: [NzEmptyComponent, NzEmbedEmptyComponent, NzEmptyDefaultComponent, NzEmptySimpleComponent],
exports: [NzEmptyComponent, NzEmbedEmptyComponent]
})
export class NzEmptyModule {}
Loading

0 comments on commit 048902e

Please sign in to comment.