Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(module:empty): refactor #4726

Merged
merged 4 commits into from
Feb 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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