From 9e71deb2e92a3108d60af29f95aa3af884d066fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=A1=E8=89=B2?= Date: Sat, 3 Mar 2018 01:02:23 +0800 Subject: [PATCH] feat(module:list): add list component (#1031) * wip(module:list): add list component - add third libs with share.module * fix lint & clean invalid code * Use NzUpdateHostClassService Instead of class operation * update test status * fix string and template invalid switched * fix tslint * fix nz-card --- PROGRESS.md | 2 +- components/list/demo/grid.ts | 6 +- components/list/demo/infinite-load.md | 14 + components/list/demo/infinite-load.ts | 78 ++++++ components/list/demo/loadmore.ts | 12 +- components/list/demo/resposive.ts | 20 +- components/list/demo/vertical.ts | 15 +- components/list/doc/index.en-US.md | 54 ++++ components/list/doc/index.zh-CN.md | 4 +- components/list/index.ts | 6 +- components/list/list.spec.ts | 262 ++++++++++++++++++ .../list/nz-list-item-meta.component.ts | 77 ++--- components/list/nz-list-item.component.ts | 81 +++--- components/list/nz-list.component.ts | 113 ++++---- components/list/nz-list.module.ts | 5 +- components/list/public-api.ts | 5 + components/list/style/bordered.less | 72 ++--- components/list/style/index.less | 3 +- components/list/style/responsive.less | 64 ++--- package.json | 3 +- scripts/_site/src/app/app.module.ts | 13 +- scripts/_site/src/app/share/share.module.ts | 43 +++ scripts/template/demo-module.template.ts | 12 +- scripts/template/doc-module.template.ts | 8 +- 24 files changed, 700 insertions(+), 272 deletions(-) create mode 100644 components/list/demo/infinite-load.md create mode 100644 components/list/demo/infinite-load.ts create mode 100644 components/list/list.spec.ts create mode 100644 components/list/public-api.ts create mode 100644 scripts/_site/src/app/share/share.module.ts diff --git a/PROGRESS.md b/PROGRESS.md index 694f61d98ad..08ea7a23c50 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -43,7 +43,7 @@ | affix | x | x | x | cipchk | - | | transfer | x | x | x | cipchk | - | | avatar | √ | 100% | 100% | cipchk | x | -| list | x | x | x | cipchk | - | +| list | √ | 100% | 100% | cipchk | x | | upload | x | x | x | cipchk | - | | anchor | x | x | x | cipchk | - | | backtop | x | x | x | cipchk | - | diff --git a/components/list/demo/grid.ts b/components/list/demo/grid.ts index 2bd07a6d2a4..faa42ea6521 100644 --- a/components/list/demo/grid.ts +++ b/components/list/demo/grid.ts @@ -1,4 +1,3 @@ -// tslint:disable import { Component } from '@angular/core'; @Component({ @@ -8,9 +7,8 @@ import { Component } from '@angular/core'; - - {{item.title}} - Card content + + Card content diff --git a/components/list/demo/infinite-load.md b/components/list/demo/infinite-load.md new file mode 100644 index 00000000000..bf6513e415a --- /dev/null +++ b/components/list/demo/infinite-load.md @@ -0,0 +1,14 @@ +--- +order: 6 +title: + zh-CN: 滚动加载 + en-US: Scrolling loaded +--- + +## zh-CN + +结合 [ngx-infinite-scroll](https://github.com/orizens/ngx-infinite-scroll) 实现滚动自动加载列表。 + +## en-US + +The example of infinite load with [ngx-infinite-scroll](https://github.com/orizens/ngx-infinite-scroll). diff --git a/components/list/demo/infinite-load.ts b/components/list/demo/infinite-load.ts new file mode 100644 index 00000000000..94d33649d6c --- /dev/null +++ b/components/list/demo/infinite-load.ts @@ -0,0 +1,78 @@ +// tslint:disable:no-any +import { HttpClient } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; +import { NzMessageService } from 'ng-zorro-antd'; + +const fakeDataUrl = 'https://randomuser.me/api/?results=5&inc=name,gender,email,nat&noinfo'; + +@Component({ + selector: 'nz-demo-list-infinite-load', + template: ` +
+ + + + + + {{item.name.last}} + + + + + + +
+ `, + styles: [ ` + :host ::ng-deep .demo-infinite-container { + border: 1px solid #e8e8e8; + border-radius: 4px; + overflow: auto; + padding: 8px 24px; + height: 300px; + } + :host ::ng-deep .demo-loading { + position: absolute; + bottom: -40px; + left: 50%; + } + ` ] +}) +export class NzDemoListInfiniteLoadComponent implements OnInit { + data: any[] = []; + loading = false; + hasMore = true; + + constructor(private http: HttpClient, private msg: NzMessageService) {} + + ngOnInit(): void { + this.getData((res: any) => this.data = res.results); + } + + getData(callback: (res: any) => void): void { + this.http.get(fakeDataUrl).subscribe((res: any) => callback(res)); + } + + onScroll(): void { + if (this.loading) return; + this.loading = true; + if (this.data.length > 14) { + this.msg.warning('Infinite List loaded all'); + this.hasMore = false; + this.loading = false; + return; + } + this.getData((res: any) => { + this.data = this.data.concat(res.results); + this.loading = false; + }); + } +} diff --git a/components/list/demo/loadmore.ts b/components/list/demo/loadmore.ts index 2a0beb0ce71..a22fb396535 100644 --- a/components/list/demo/loadmore.ts +++ b/components/list/demo/loadmore.ts @@ -1,6 +1,6 @@ -// tslint:disable -import { Component, OnInit, ViewEncapsulation } from '@angular/core'; +// tslint:disable:no-any import { HttpClient } from '@angular/common/http'; +import { Component, OnInit } from '@angular/core'; import { NzMessageService } from 'ng-zorro-antd'; const fakeDataUrl = 'https://randomuser.me/api/?results=5&inc=name,gender,email,nat&noinfo'; @@ -55,18 +55,18 @@ export class NzDemoListLoadmoreComponent implements OnInit { constructor(private http: HttpClient, private msg: NzMessageService) {} - ngOnInit() { + ngOnInit(): void { this.getData((res: any) => { this.data = res.results; this.loading = false; }); } - getData(callback: (res: any) => void) { + getData(callback: (res: any) => void): void { this.http.get(fakeDataUrl).subscribe((res: any) => callback(res)); } - onLoadMore() { + onLoadMore(): void { this.loadingMore = true; this.http.get(fakeDataUrl).subscribe((res: any) => { this.data = this.data.concat(res.results); @@ -74,7 +74,7 @@ export class NzDemoListLoadmoreComponent implements OnInit { }); } - edit(item: any) { + edit(item: any): void { this.msg.success(item.email); } } diff --git a/components/list/demo/resposive.ts b/components/list/demo/resposive.ts index 6d75977172e..5e60d8ffbaa 100644 --- a/components/list/demo/resposive.ts +++ b/components/list/demo/resposive.ts @@ -1,4 +1,3 @@ -// tslint:disable import { Component } from '@angular/core'; @Component({ @@ -8,9 +7,8 @@ import { Component } from '@angular/core'; - - {{item.title}} - Card content + + Card content @@ -21,22 +19,22 @@ import { Component } from '@angular/core'; export class NzDemoListResposiveComponent { data = [ { - title: 'Title 1', + title: 'Title 1' }, { - title: 'Title 2', + title: 'Title 2' }, { - title: 'Title 3', + title: 'Title 3' }, { - title: 'Title 4', + title: 'Title 4' }, { - title: 'Title 5', + title: 'Title 5' }, { - title: 'Title 6', - }, + title: 'Title 6' + } ]; } diff --git a/components/list/demo/vertical.ts b/components/list/demo/vertical.ts index cc271507b1b..6af8bc45114 100644 --- a/components/list/demo/vertical.ts +++ b/components/list/demo/vertical.ts @@ -1,4 +1,3 @@ -// tslint:disable import { Component } from '@angular/core'; @Component({ @@ -29,12 +28,12 @@ import { Component } from '@angular/core'; }) export class NzDemoListVerticalComponent { data = new Array(5).fill({}).map((i, index) => { - return { - href: 'http://ant.design', - title: `ant design part ${index}`, - avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', - description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.', - content: 'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.', - }; + return { + href: 'http://ant.design', + title: `ant design part ${index}`, + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', + description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.', + content: 'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.' + }; }); } diff --git a/components/list/doc/index.en-US.md b/components/list/doc/index.en-US.md index c91ee4872cf..07f39bfbcd7 100644 --- a/components/list/doc/index.en-US.md +++ b/components/list/doc/index.en-US.md @@ -4,3 +4,57 @@ type: Data Display title: List cols: 1 --- + +Simple List. + +## When To Use + +A list can be used to display content related to a single subject. The content can consist of multiple elements of varying type and size. + +## API + +### List + +| Property | Description | Type | Default +| --- | --- | --- | --- | +| nzDataSource | Data source for list | `any[]` | - | +| item | Custom item renderer | `TemplateRef` | - | +| nzBordered | Toggles rendering of the border around the list | boolean | false | +| nzFooter | List footer renderer | `string,TemplateRef` | - | +| nzGrid | The grid type of list. You can set grid to something like `{gutter: 16, column: 4}` | object | - | +| nzHeader | List header renderer | `string,TemplateRef` | - | +| nzItemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - | +| nzLoading | Shows a loading indicator while the contents of the list are being fetched | boolean | false | +| loadMore | Shows a load more content | `TemplateRef` | - | +| pagination | Shows a pagination content | `TemplateRef` | - | +| nzSize | Size of list | `default,small,large` | `default` | +| nzSplit | Toggles rendering of the split under the list item | boolean | true | + +### List grid props + +| Property | Description | Type | Default +| --- | --- | --- | --- | +| column | column of grid | number | - | +| gutter | spacing between grid | number | 0 | +| xs | `<576px` column of grid | number | - | +| sm | `≥576px` column of grid | number | - | +| md | `≥768px` column of grid | number | - | +| lg | `≥992px` column of grid | number | - | +| xl | `≥1200px` column of grid | number | - | +| xxl | `≥1600px` column of grid | number | - | + +### nz-list-item + +| Property | Description | Type | Default +| --- | --- | --- | --- | +| nzContent | content renderer | `string,TemplateRef` | - | +| action | The actions content of list item. If `itemLayout` is `vertical`, shows the content on bottom, otherwise shows content on the far right. | `TemplateRef` | - | +| extra | The extra content of list item. If `itemLayout` is `vertical`, shows the content on right, otherwise shows content on the far right. | `TemplateRef` | - | + +### nz-list-item-meta + +| Property | Description | Type | Default +| --- | --- | --- | --- | +| nzAvatar | The avatar of list item | `string,TemplateRef` | - | +| nzDescription | The description of list item | `string,TemplateRef` | - | +| nzTitle | The title of list item | `string,TemplateRef` | - | diff --git a/components/list/doc/index.zh-CN.md b/components/list/doc/index.zh-CN.md index abc3dcce957..17266af07af 100644 --- a/components/list/doc/index.zh-CN.md +++ b/components/list/doc/index.zh-CN.md @@ -24,11 +24,11 @@ cols: 1 | nzFooter | 列表底部 | `string,TemplateRef` | - | | nzGrid | 列表栅格配置 | object | - | | nzHeader | 列表头部 | `string,TemplateRef` | - | -| nzItemLayout | 设置 `nz-list-item` 布局, 设置成 `vertical` 则竖直样式显示, 默认横排 | string | horizontal | +| nzItemLayout | 设置 `nz-list-item` 布局, 设置成 `vertical` 则竖直样式显示, 默认横排 | string | - | | nzLoading | 当卡片内容还在加载中时,可以用 `loading` 展示一个占位 | boolean | false | | loadMore | 加载更多 | `TemplateRef` | - | | pagination | 对应的 `pagination` 配置 | `TemplateRef` | - | -| nzSize | list 的尺寸 | `default,middle,small` | `default` | +| nzSize | list 的尺寸 | `default,small,large` | `default` | | nzSplit | 是否展示分割线 | boolean | true | ### List grid props diff --git a/components/list/index.ts b/components/list/index.ts index 3e91d362559..7e1a213e3ea 100644 --- a/components/list/index.ts +++ b/components/list/index.ts @@ -1,5 +1 @@ -export { NzListItemMetaComponent } from './nz-list-item-meta.component'; -export { NzListItemComponent } from './nz-list-item.component'; -export { NzListComponent } from './nz-list.component'; -export * from './interface'; -export { NzListModule } from './nz-list.module'; +export * from './public-api'; diff --git a/components/list/list.spec.ts b/components/list/list.spec.ts new file mode 100644 index 00000000000..67d7ebfc164 --- /dev/null +++ b/components/list/list.spec.ts @@ -0,0 +1,262 @@ +import { Component, DebugElement, TemplateRef, ViewChild } from '@angular/core'; +import { fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { NzListModule } from './nz-list.module'; + +describe('list', () => { + let fixture: ComponentFixture; + let context: TestListComponent; + let dl: DebugElement; + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ NzListModule ], + declarations: [ TestListComponent, TestListWithTemplateComponent, TestListItemComponent ] + }).compileComponents(); + fixture = TestBed.createComponent(TestListComponent); + context = fixture.componentInstance; + dl = fixture.debugElement; + fixture.detectChanges(); + }); + + describe('[fields]', () => { + + describe('#nzItemLayout', () => { + for (const item of [ { type: 'default', ret: false }, { type: 'vertical', ret: true } ]) { + it(`[${item.type}]`, () => { + context.nzItemLayout = item.type; + fixture.detectChanges(); + expect(dl.query(By.css(`.ant-list-${item.type}`)) != null).toBe(item.ret); + }); + } + }); + + describe('#nzBordered', () => { + for (const value of [ true, false ]) { + it(`[${value}]`, () => { + context.nzBordered = value; + fixture.detectChanges(); + expect(dl.query(By.css('.ant-list-bordered')) != null).toBe(value); + }); + } + }); + + describe('#nzHeader', () => { + it('with string', () => { + expect(dl.query(By.css('.ant-list-header')) != null).toBe(true); + }); + it('with custom template', () => { + const fixtureTemp = TestBed.createComponent(TestListWithTemplateComponent); + fixtureTemp.detectChanges(); + expect(fixtureTemp.debugElement.query(By.css('.list-header')) != null).toBe(true); + }); + }); + + describe('#nzFooter', () => { + it('with string', () => { + expect(dl.query(By.css('.ant-list-footer')) != null).toBe(true); + }); + it('with custom template', () => { + const fixtureTemp = TestBed.createComponent(TestListWithTemplateComponent); + fixtureTemp.detectChanges(); + const footerEl = fixtureTemp.debugElement.query(By.css('.ant-list-footer')); + expect((footerEl.nativeElement as HTMLDivElement).innerText).toBe(fixtureTemp.componentInstance.footer as string); + }); + it('change string to template', () => { + const fixtureTemp = TestBed.createComponent(TestListWithTemplateComponent); + fixtureTemp.detectChanges(); + const footerEl = fixtureTemp.debugElement.query(By.css('.ant-list-footer')); + expect((footerEl.nativeElement as HTMLDivElement).innerText).toBe(fixtureTemp.componentInstance.footer as string); + (fixtureTemp.debugElement.query(By.css('#change')).nativeElement as HTMLButtonElement).click(); + fixtureTemp.detectChanges(); + expect(fixtureTemp.debugElement.query(By.css('.list-footer')) != null).toBe(true); + }); + }); + + describe('#nzSize', () => { + for (const item of [ + { type: 'default', cls: '.ant-list' }, + { type: 'small', cls: '.ant-list-sm' }, + { type: 'large', cls: '.ant-list-lg' } + ]) { + it(`[${item.type}]`, () => { + context.nzSize = item.type; + fixture.detectChanges(); + expect(dl.query(By.css(item.cls)) != null).toBe(true); + }); + } + }); + + describe('#nzSplit', () => { + for (const value of [ true, false ]) { + it(`[${value}]`, () => { + context.nzSplit = value; + fixture.detectChanges(); + expect(dl.query(By.css('.ant-list-split')) != null).toBe(value); + }); + } + }); + + describe('#nzLoading', () => { + for (const value of [ true, false ]) { + it(`[${value}]`, () => { + context.nzLoading = value; + fixture.detectChanges(); + expect(dl.query(By.css('.ant-list-loading')) != null).toBe(value); + }); + } + }); + + it('#nzDataSource', () => { + expect(dl.queryAll(By.css('nz-list-item')).length).toBe(context.data.length); + }); + + it('#nzGrid', () => { + const colCls = `.ant-col-${context.nzGrid.span}`; + expect(dl.queryAll(By.css(colCls)).length).toBe(context.data.length); + }); + + it('#loadMore', () => { + expect(dl.query(By.css('.loadmore')) != null).toBe(true); + }); + + it('#pagination', () => { + expect(dl.query(By.css('.pagination')) != null).toBe(true); + }); + }); + + describe('item', () => { + let fixtureTemp: ComponentFixture; + beforeEach(() => { + fixtureTemp = TestBed.createComponent(TestListItemComponent); + fixtureTemp.detectChanges(); + }); + it('with string', () => { + expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-content')) != null).toBe(true); + expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-action')) != null).toBe(true); + expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-extra')) != null).toBe(true); + }); + it('with custom template of [nzContent]', () => { + expect(fixtureTemp.debugElement.query(By.css('#item-template .ant-list-item-content .item-content')) != null).toBe(true); + }); + }); + + describe('item-meta', () => { + let fixtureTemp: ComponentFixture; + beforeEach(() => { + fixtureTemp = TestBed.createComponent(TestListItemComponent); + fixtureTemp.detectChanges(); + }); + it('with string', () => { + expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-meta-title')) != null).toBe(true); + expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-meta-description')) != null).toBe(true); + expect(fixtureTemp.debugElement.query(By.css('#item-string .ant-list-item-meta-avatar')) != null).toBe(true); + }); + it('with custom template', () => { + expect(fixtureTemp.debugElement.query(By.css('#item-template .item-title')) != null).toBe(true); + expect(fixtureTemp.debugElement.query(By.css('#item-template .item-desc')) != null).toBe(true); + expect(fixtureTemp.debugElement.query(By.css('#item-template .item-avatar')) != null).toBe(true); + }); + }); + +}); + +@Component({ + template: ` + + + + + + + + +
loadmore
+
+ + + +
+ ` +}) +class TestListComponent { + nzItemLayout = 'horizontal'; + nzBordered = false; + nzFooter = 'footer'; + nzHeader = 'header'; + nzLoading = false; + nzSize = 'default'; + nzSplit = true; + data = [ + 'Racing car sprays burning fuel into crowd.', + 'Japanese princess to wed commoner.', + 'Racing car sprays burning fuel into crowd.', + 'Japanese princess to wed commoner.' + ]; + // tslint:disable-next-line:no-any + nzGrid: any = {gutter: 16, span: 12}; +} + +@Component({ + template: ` + + + +

header

+
+ ` +}) +class TestListWithTemplateComponent { + + @ViewChild('nzFooter') nzFooter: TemplateRef; + + footer: string | TemplateRef = 'footer with string'; + +} + +@Component({ + template: ` + + + 156 + + logo + + + + + + + +

nzContent

+ +

nzTitle

+

nzAvatar

+

nzDescription

+
+
+
+ ` +}) +class TestListItemComponent { +} diff --git a/components/list/nz-list-item-meta.component.ts b/components/list/nz-list-item-meta.component.ts index a9b19384397..52de70c4fcd 100644 --- a/components/list/nz-list-item-meta.component.ts +++ b/components/list/nz-list-item-meta.component.ts @@ -1,61 +1,68 @@ -// tslint:disable:ordered-imports no-any import { Component, ContentChild, HostBinding, Input, TemplateRef } from '@angular/core'; @Component({ selector: 'nz-list-item-meta', template: ` -
- -
-
-

- {{ _title }} -

-
- {{ _desc }} -
-
- ` +
+ +
+
+

+ {{ titleStr }} +

+
+ {{ descStr }} +
+
`, + preserveWhitespaces: false, + host: { + '[class.ant-list-item-meta]': 'true' + } }) export class NzListItemMetaComponent { - @HostBinding('class.ant-list-item-meta') _nzListItemMeta = true; - avatar = false; - _avatar = ''; - _avatarTpl: TemplateRef; + isAvatar = false; + avatarStr = ''; + avatarTpl: TemplateRef; @Input() - set nzAvatar(value: string | TemplateRef) { + set nzAvatar(value: string | TemplateRef) { if (value instanceof TemplateRef) { - this._avatarTpl = value; + this.avatarStr = null; + this.avatarTpl = value; } else { - this._avatar = value; + this.avatarStr = value; } - this.avatar = !!value; + this.isAvatar = !!value; } - title = false; - _title = ''; - _titleTpl: TemplateRef; + isTitle = false; + titleStr = ''; + titleTpl: TemplateRef; @Input() - set nzTitle(value: string | TemplateRef) { + set nzTitle(value: string | TemplateRef) { if (value instanceof TemplateRef) { - this._titleTpl = value; + this.titleStr = null; + this.titleTpl = value; } else { - this._title = value; + this.titleStr = value; } - this.title = !!value; + this.isTitle = !!value; } - desc = false; - _desc = ''; - _descTpl: TemplateRef; + isDesc = false; + descStr = ''; + descTpl: TemplateRef; @Input() - set nzDescription(value: string | TemplateRef) { - if (value instanceof TemplateRef) this._descTpl = value; - else this._desc = value; + set nzDescription(value: string | TemplateRef) { + if (value instanceof TemplateRef) { + this.descStr = null; + this.descTpl = value; + } else { + this.descStr = value; + } - this.desc = !!value; + this.isDesc = !!value; } } diff --git a/components/list/nz-list-item.component.ts b/components/list/nz-list-item.component.ts index c8a409e53c4..0e3d09b6aa9 100644 --- a/components/list/nz-list-item.component.ts +++ b/components/list/nz-list-item.component.ts @@ -1,64 +1,55 @@ -// tslint:disable:ordered-imports no-any -import { Component, ContentChild, ContentChildren, HostBinding, Input, QueryList, TemplateRef, ViewChild, ElementRef } from '@angular/core'; +import { Component, ContentChild, ContentChildren, ElementRef, HostBinding, Input, QueryList, TemplateRef, ViewChild } from '@angular/core'; + import { NzListItemMetaComponent } from './nz-list-item-meta.component'; @Component({ selector: 'nz-list-item', template: ` - -
- {{ _content }} -
-
- -
    -
  • - - -
  • -
-
- - - - - -
-
-
+ +
+ {{ conStr }}
- ` +
+ +
    +
  • + + +
  • +
+
+ + + + + +
+
+
+
`, + preserveWhitespaces: false, + host: { + '[class.ant-list-item]': 'true' + } }) export class NzListItemComponent { - /** @private */ - @HostBinding('class.ant-list-item') _nzListItem = true; @ContentChildren('action') actions: QueryList; @ContentChildren(NzListItemMetaComponent) metas: QueryList; - content = false; - _content = ''; - _contentTpl: TemplateRef; + isCon = false; + conStr = ''; + conTpl: TemplateRef; @Input() - set nzContent(value: string | TemplateRef) { + set nzContent(value: string | TemplateRef) { if (value instanceof TemplateRef) { - this._contentTpl = value; + this.conStr = null; + this.conTpl = value; } else { - this._content = value; + this.conStr = value; } - this.content = !!value; + this.isCon = !!value; } - @ContentChild('extra') extra: TemplateRef; - - isEmpty(element: HTMLElement): boolean { - const nodes = element.childNodes; - for (let i = 0; i < nodes.length; i++) { - const node = nodes.item(i); - if (node.nodeType !== 8 && nodes.item(i).textContent.trim().length !== 0) { - return false; - } - } - return true; - } + @ContentChild('extra') extra: TemplateRef; } diff --git a/components/list/nz-list.component.ts b/components/list/nz-list.component.ts index 00ac7475056..b413b371bc0 100644 --- a/components/list/nz-list.component.ts +++ b/components/list/nz-list.component.ts @@ -1,45 +1,48 @@ -// tslint:disable:ordered-imports no-any -import { Component, ViewEncapsulation, Input, TemplateRef, ChangeDetectionStrategy, ChangeDetectorRef, ContentChild, ElementRef, Renderer2, OnChanges, SimpleChanges, OnInit } from '@angular/core'; +// tslint:disable: no-any +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, Input, OnChanges, SimpleChanges, TemplateRef } from '@angular/core'; + +import { NzUpdateHostClassService } from '../core/services/update-host-class.service'; import { toBoolean } from '../core/util/convert'; -import { NzListGrid, ListSize } from './interface'; + +import { ListSize, NzListGrid } from './interface'; @Component({ selector: 'nz-list', template: ` - - - - - -
- {{ _header }} -
- -
-
- -
+ + + + + +
+ {{ _header }} +
+ +
+
+
- - - -
-
- - `, - styleUrls: ['./style/index.less', './style/patch.less'], - encapsulation: ViewEncapsulation.None, + + + +
+ +
+ + `, + providers : [ NzUpdateHostClassService ], + preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush }) -export class NzListComponent implements OnChanges, OnInit { +export class NzListComponent implements OnChanges { // region: fields @Input() nzDataSource: any[] = []; @@ -54,32 +57,34 @@ export class NzListComponent implements OnChanges, OnInit { @Input() nzGrid: NzListGrid; - header = false; + _isHeader = false; _header = ''; _headerTpl: TemplateRef; @Input() set nzHeader(value: string | TemplateRef) { if (value instanceof TemplateRef) { + this._header = null; this._headerTpl = value; } else { this._header = value; } - this.header = !!value; + this._isHeader = !!value; } - footer = false; + _isFooter = false; _footer = ''; _footerTpl: TemplateRef; @Input() set nzFooter(value: string | TemplateRef) { if (value instanceof TemplateRef) { + this._footer = null; this._footerTpl = value; } else { this._footer = value; } - this.footer = !!value; + this._isFooter = !!value; } @Input() nzItemLayout: 'vertical' | 'horizontal' = 'horizontal'; @@ -112,34 +117,28 @@ export class NzListComponent implements OnChanges, OnInit { // region: styles - _prefixCls = 'ant-list'; - _classList: string[] = []; + private prefixCls = 'ant-list'; private _setClassMap(): void { - this._classList.forEach(cls => this._renderer.removeClass(this._el.nativeElement, cls)); - - this._classList = [ - this._prefixCls, - this.nzItemLayout === 'vertical' && `${this._prefixCls}-vertical`, - this.nzSize === 'large' && `${this._prefixCls}-lg`, - this.nzSize === 'small' && `${this._prefixCls}-sm`, - this.nzSplit && `${this._prefixCls}-split`, - this.nzBordered && `${this._prefixCls}-bordered`, - this.nzLoading && `${this._prefixCls}-loading`, - this.nzGrid && `${this._prefixCls}-grid`, - !!(this.nzLoadMore || this.nzPagination || this.footer) && `${this._prefixCls}-something-after-last-item` - ].filter(item => !!item); - - this._classList.forEach(cls => this._renderer.addClass(this._el.nativeElement, cls)); + const classMap = { + [this.prefixCls]: true, + [`${this.prefixCls}-vertical`]: this.nzItemLayout === 'vertical', + [`${this.prefixCls}-lg`]: this.nzSize === 'large', + [`${this.prefixCls}-sm`]: this.nzSize === 'small', + [`${this.prefixCls}-split`]: this.nzSplit, + [`${this.prefixCls}-bordered`]: this.nzBordered, + [`${this.prefixCls}-loading`]: this.nzLoading, + [`${this.prefixCls}-grid`]: this.nzGrid, + [`${this.prefixCls}-something-after-last-item`]: !!(this.nzLoadMore || this.nzPagination || this._isFooter) + }; + this.updateHostClassService.updateHostClass(this.el.nativeElement, classMap); this.cd.detectChanges(); } // endregion - constructor(private _el: ElementRef, private _renderer: Renderer2, private cd: ChangeDetectorRef) {} - - ngOnInit(): void {} + constructor(private el: ElementRef, private cd: ChangeDetectorRef, private updateHostClassService: NzUpdateHostClassService) {} ngOnChanges(changes: SimpleChanges): void { this._setClassMap(); diff --git a/components/list/nz-list.module.ts b/components/list/nz-list.module.ts index 0aed2152990..c8291515780 100644 --- a/components/list/nz-list.module.ts +++ b/components/list/nz-list.module.ts @@ -1,14 +1,13 @@ -// tslint:disable:ordered-imports import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { NzSpinModule } from '../spin/nz-spin.module'; import { NzAvatarModule } from '../avatar/nz-avatar.module'; import { NzGridModule } from '../grid/nz-grid.module'; +import { NzSpinModule } from '../spin/nz-spin.module'; -import { NzListComponent } from './nz-list.component'; import { NzListItemMetaComponent } from './nz-list-item-meta.component'; import { NzListItemComponent } from './nz-list-item.component'; +import { NzListComponent } from './nz-list.component'; @NgModule({ imports: [ CommonModule, NzSpinModule, NzGridModule, NzAvatarModule ], diff --git a/components/list/public-api.ts b/components/list/public-api.ts new file mode 100644 index 00000000000..b168d0e83c3 --- /dev/null +++ b/components/list/public-api.ts @@ -0,0 +1,5 @@ +export * from './interface'; +export { NzListItemMetaComponent } from './nz-list-item-meta.component'; +export { NzListItemComponent } from './nz-list-item.component'; +export { NzListComponent } from './nz-list.component'; +export { NzListModule } from './nz-list.module'; diff --git a/components/list/style/bordered.less b/components/list/style/bordered.less index 552573ed081..856bc502ea1 100644 --- a/components/list/style/bordered.less +++ b/components/list/style/bordered.less @@ -1,41 +1,41 @@ .@{list-prefix-cls}-bordered { - border-radius: @border-radius-base; - border: 1px solid @border-color-base; - .@{list-prefix-cls}-header { - padding-left: 24px; - padding-right: 24px; - } - - .@{list-prefix-cls}-footer { - padding-left: 24px; - padding-right: 24px; - } - + border-radius: @border-radius-base; + border: 1px solid @border-color-base; + .@{list-prefix-cls}-header { + padding-left: 24px; + padding-right: 24px; + } + + .@{list-prefix-cls}-footer { + padding-left: 24px; + padding-right: 24px; + } + + .@{list-prefix-cls}-item { + border-bottom: 1px solid @border-color-split; + padding-left: 24px; + padding-right: 24px; + } + + .@{list-prefix-cls}-pagination { + margin: 16px 24px; + } + + &.@{list-prefix-cls}-sm { .@{list-prefix-cls}-item { - border-bottom: 1px solid @border-color-split; - padding-left: 24px; - padding-right: 24px; + padding-left: 16px; + padding-right: 16px; } - - .@{list-prefix-cls}-pagination { - margin: 16px 24px; - } - - &.@{list-prefix-cls}-sm { - .@{list-prefix-cls}-item { - padding-left: 16px; - padding-right: 16px; - } - .@{list-prefix-cls}-header, - .@{list-prefix-cls}-footer { - padding: 8px 16px; - } + .@{list-prefix-cls}-header, + .@{list-prefix-cls}-footer { + padding: 8px 16px; } - - &.@{list-prefix-cls}-lg { - .@{list-prefix-cls}-header, - .@{list-prefix-cls}-footer { - padding: 16px 24px; - } + } + + &.@{list-prefix-cls}-lg { + .@{list-prefix-cls}-header, + .@{list-prefix-cls}-footer { + padding: 16px 24px; } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/components/list/style/index.less b/components/list/style/index.less index 09fc3ade7db..ab606da9df0 100644 --- a/components/list/style/index.less +++ b/components/list/style/index.less @@ -204,4 +204,5 @@ } @import './bordered'; -@import './responsive'; \ No newline at end of file +@import './responsive'; +@import './patch'; \ No newline at end of file diff --git a/components/list/style/responsive.less b/components/list/style/responsive.less index a7879c0d57e..b913edada4e 100644 --- a/components/list/style/responsive.less +++ b/components/list/style/responsive.less @@ -1,42 +1,42 @@ @media screen and (max-width: @screen-md) { - .@{list-prefix-cls} { - &-item { - &-action { - margin-left: 24px; - } + .@{list-prefix-cls} { + &-item { + &-action { + margin-left: 24px; } } - - .@{list-prefix-cls}-vertical { - .@{list-prefix-cls}-item { - &-extra { - margin-left: 24px; - } + } + + .@{list-prefix-cls}-vertical { + .@{list-prefix-cls}-item { + &-extra { + margin-left: 24px; } } } - - @media screen and (max-width: @screen-xs) { - .@{list-prefix-cls} { - &-item { - flex-wrap: wrap; - &-action { - margin-left: 12px; - } +} + +@media screen and (max-width: @screen-xs) { + .@{list-prefix-cls} { + &-item { + flex-wrap: wrap; + &-action { + margin-left: 12px; } } - - .@{list-prefix-cls}-vertical { - .@{list-prefix-cls}-item { - &-extra-wrap { - flex-wrap: wrap-reverse; - } - &-main { - min-width: 220px; - } - &-extra { - margin-left: 0; - } + } + + .@{list-prefix-cls}-vertical { + .@{list-prefix-cls}-item { + &-extra-wrap { + flex-wrap: wrap-reverse; + } + &-main { + min-width: 220px; + } + &-extra { + margin-left: 0; } } - } \ No newline at end of file + } +} \ No newline at end of file diff --git a/package.json b/package.json index df642fe9cdf..6d7f0a2de24 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,8 @@ "web-animations-js": "^2.3.1", "wrench": "^1.5.9", "yaml-front-matter": "^3.4.0", - "zone.js": "^0.8.19" + "zone.js": "^0.8.19", + "ngx-infinite-scroll": "^0.8.2" }, "peerDependencies": { "@angular/animations": "^5.0.0", diff --git a/scripts/_site/src/app/app.module.ts b/scripts/_site/src/app/app.module.ts index 47cebaa431a..ff38d79b1e4 100644 --- a/scripts/_site/src/app/app.module.ts +++ b/scripts/_site/src/app/app.module.ts @@ -4,16 +4,13 @@ import { FormsModule } from '@angular/forms'; import { BrowserModule, Title } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { PreloadAllModules, RouterModule } from '@angular/router'; -import { - NgZorroAntdModule -} from 'ng-zorro-antd'; +import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { ShareModule } from './share/share.module'; + import { AppComponent } from './app.component'; import { DEMOComponent } from './_demo/demo.component'; import { routes } from './app.routing.module'; import { environment } from '../environments/environment'; -import { NzCodeBoxModule } from './share/nz-codebox/nz-codebox.module'; -import { NzHighlightModule } from './share/nz-highlight/nz-highlight.module'; -import { NzNavBottomModule } from './share/nz-nav-bottom/nz-nav-bottom.module'; @NgModule({ declarations: [ @@ -24,10 +21,8 @@ import { NzNavBottomModule } from './share/nz-nav-bottom/nz-nav-bottom.module'; BrowserAnimationsModule, FormsModule, HttpClientModule, + ShareModule, NgZorroAntdModule.forRoot(), - NzCodeBoxModule, - NzHighlightModule, - NzNavBottomModule, RouterModule.forRoot(routes, environment.production ? { preloadingStrategy: PreloadAllModules } : {}) ], providers : [ diff --git a/scripts/_site/src/app/share/share.module.ts b/scripts/_site/src/app/share/share.module.ts new file mode 100644 index 00000000000..85730b76b05 --- /dev/null +++ b/scripts/_site/src/app/share/share.module.ts @@ -0,0 +1,43 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; +import { + NgZorroAntdModule +} from 'ng-zorro-antd'; +import { InfiniteScrollModule } from 'ngx-infinite-scroll'; + +import { NzCodeBoxModule } from './nz-codebox/nz-codebox.module'; +import { NzHighlightModule } from './nz-highlight/nz-highlight.module'; +import { NzNavBottomModule } from './nz-nav-bottom/nz-nav-bottom.module'; +import { NzCopyIconModule } from './nz-copy-icon/nz-copy-icon.module'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + RouterModule, + ReactiveFormsModule, + NgZorroAntdModule, + NzCodeBoxModule, + NzHighlightModule, + NzNavBottomModule, + NzCopyIconModule, + // third libs + InfiniteScrollModule, + ], + exports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + RouterModule, + NgZorroAntdModule, + NzCodeBoxModule, + NzHighlightModule, + NzNavBottomModule, + NzCopyIconModule, + // third libs + InfiniteScrollModule, + ] +}) +export class ShareModule { } diff --git a/scripts/template/demo-module.template.ts b/scripts/template/demo-module.template.ts index ebc94d5443a..fb799505d46 100644 --- a/scripts/template/demo-module.template.ts +++ b/scripts/template/demo-module.template.ts @@ -1,21 +1,13 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; -import { NzCodeBoxModule } from '../share/nz-codebox/nz-codebox.module'; -import { NzCopyIconModule } from '../share/nz-copy-icon/nz-copy-icon.module'; -import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { ShareModule } from '../share/share.module'; {{imports}} @NgModule({ imports : [ - NgZorroAntdModule, - CommonModule, - FormsModule, - ReactiveFormsModule, - NzCodeBoxModule, - NzCopyIconModule, + ShareModule, RouterModule.forChild([ { path: 'en', component: NzDemo{{component}}EnComponent }, { path: 'zh', component: NzDemo{{component}}ZhComponent } diff --git a/scripts/template/doc-module.template.ts b/scripts/template/doc-module.template.ts index 137b34f49bb..70da6ccd149 100644 --- a/scripts/template/doc-module.template.ts +++ b/scripts/template/doc-module.template.ts @@ -1,16 +1,12 @@ import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; -import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { ShareModule } from '../share/share.module'; {{imports}} @NgModule({ imports : [ - NgZorroAntdModule, - CommonModule, - FormsModule, + ShareModule, RouterModule.forChild([ {{router}} ])