diff --git a/components/ng-zorro-antd.module.ts b/components/ng-zorro-antd.module.ts index 1dfc0261bcc..a51a87408af 100644 --- a/components/ng-zorro-antd.module.ts +++ b/components/ng-zorro-antd.module.ts @@ -14,6 +14,7 @@ import { NzCarouselModule } from './carousel/nz-carousel.module'; import { NzCascaderModule } from './cascader/nz-cascader.module'; import { NzCheckboxModule } from './checkbox/nz-checkbox.module'; import { NzCollapseModule } from './collapse/nz-collapse.module'; +import { NzWaveModule } from './core/wave/nz-wave.module'; import { NzDatePickerModule } from './date-picker/date-picker.module'; import { NzDividerModule } from './divider/nz-divider.module'; import { NzDrawerModule } from './drawer/nz-drawer.module'; @@ -30,6 +31,7 @@ import { NzMenuModule } from './menu/nz-menu.module'; import { NzMessageModule } from './message/nz-message.module'; import { NzModalModule } from './modal/nz-modal.module'; import { NzNotificationModule } from './notification/nz-notification.module'; +import { NzTreeSelectModule } from './tree-select/nz-tree-select.module'; import { NzPaginationModule } from './pagination/nz-pagination.module'; import { NzPopconfirmModule } from './popconfirm/nz-popconfirm.module'; import { NzPopoverModule } from './popover/nz-popover.module'; @@ -49,10 +51,8 @@ import { NzTimePickerModule } from './time-picker/nz-time-picker.module'; import { NzTimelineModule } from './timeline/nz-timeline.module'; import { NzToolTipModule } from './tooltip/nz-tooltip.module'; import { NzTransferModule } from './transfer/nz-transfer.module'; -import { NzTreeSelectModule } from './tree-select/nz-tree-select.module'; import { NzTreeModule } from './tree/nz-tree.module'; import { NzUploadModule } from './upload/nz-upload.module'; -import { NzWaveModule } from './core/wave/nz-wave.module'; export * from './affix'; export * from './alert'; diff --git a/components/tree-select/demo/async.ts b/components/tree-select/demo/async.ts index 374132cb383..b46c8277a54 100755 --- a/components/tree-select/demo/async.ts +++ b/components/tree-select/demo/async.ts @@ -5,80 +5,39 @@ import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; selector: 'nz-demo-tree-select-async', template: ` + nzPlaceHolder="Please select" + [nzDefaultExpandedKeys]="expandKeys" + [nzDropdownMatchSelectWidth]="true" + [nzDropdownStyle]="{ 'max-height': '300px' }" + [(ngModel)]="value" + [nzNodes]="nodes" + [nzAsyncData]="true" + (nzExpandChange)="onExpandChange($event)"> ` }) export class NzDemoTreeSelectAsyncComponent implements OnInit { - expandKeys = [ '1001', '10001' ]; + expandKeys = [ '0-0' ]; value: string; - nodes = [ - new NzTreeNode({ - title: 'root1', - key: '1001', - children: [ - { - title: 'child1', - key: '10001', - children: [ - { - title: 'child1.1', - key: '100011', - children: [] - }, - { - title: 'child1.2', - key: '100012', - children: [ - { - title: 'grandchild1.2.1', - key: '1000121', - isLeaf: true, - disabled: true - }, - { - title: 'grandchild1.2.2', - key: '1000122', - isLeaf: true - } - ] - } - ] - } - ] - }), - new NzTreeNode({ - title: 'root2', - key: '1002', - children: [ - { - title: 'child2.1', - key: '10021', - children: [], - disabled: true - }, - { - title: 'child2.2', - key: '10022', - children: [ - { - title: 'grandchild2.2.1', - key: '100221', - isLeaf: true - } - ] - } - ] - }) - ]; + nodes = [ { + title : 'Node1', + value : '0-0', + key : '0-0', + children: [ { + title: 'Child Node1', + value: '0-0-1', + key : '0-0-1' + }, { + title: 'Child Node2', + value: '0-0-2', + key : '0-0-2' + } ] + }, { + title: 'Node2', + value: '0-1', + key : '0-1' + } ]; onExpandChange(e: NzFormatEmitEvent): void { if (e.node.getChildren().length === 0 && e.node.isExpanded) { @@ -91,39 +50,8 @@ export class NzDemoTreeSelectAsyncComponent implements OnInit { loadNode(): Promise { return new Promise(resolve => { setTimeout(() => resolve([ - new NzTreeNode({ - title: 'root2', - key: '10030-' + (new Date()).getTime(), - children: [ - { - title: 'child2.1', - key: '10021', - children: [], - checked: true, - disabled: true - }, - { - title: 'child2.2', - key: '10022', - children: [ - { - title: 'grandchild2.2.1', - key: '100221', - isLeaf: true - } - ] - } - ] - }), - { - title: 'childAdd-1', - key: '10031-' + (new Date()).getTime() - }, - { - title: 'childAdd-2', - key: '10032-' + (new Date()).getTime(), - isLeaf: true - }]), + { title: 'Child Node', key: `${(new Date()).getTime()}-0` }, + { title: 'Child Node', key: `${(new Date()).getTime()}-1` } ]), 1000); }); } diff --git a/components/tree-select/demo/basic.ts b/components/tree-select/demo/basic.ts index 2ce5b5d6a50..b6a7ef5518c 100755 --- a/components/tree-select/demo/basic.ts +++ b/components/tree-select/demo/basic.ts @@ -16,76 +16,35 @@ import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; }) export class NzDemoTreeSelectBasicComponent implements OnInit { - expandKeys = [ '1001', '10001' ]; + expandKeys = [ '100', '1001' ]; value: string; - nodes = [ - new NzTreeNode({ - title: 'root1', - key: '1001', + nodes = [ { + title : 'parent 1', + key : '100', + children: [ { + title : 'parent 1-0', + key : '1001', children: [ - { - title: 'child1', - key: '10001', - children: [ - { - title: 'child1.1', - key: '100011', - children: [] - }, - { - title: 'child1.2', - key: '100012', - children: [ - { - title: 'grandchild1.2.1', - key: '1000121', - isLeaf: true, - disabled: true - }, - { - title: 'grandchild1.2.2', - key: '1000122', - isLeaf: true - } - ] - } - ] - } + { title: 'leaf 1-0-0', key: '10010', isLeaf: true }, + { title: 'leaf 1-0-1', key: '10011', isLeaf: true } ] - }), - new NzTreeNode({ - title: 'root2', - key: '1002', + }, { + title : 'parent 1-1', + key : '1002', children: [ - { - title: 'child2.1', - key: '10021', - children: [], - disableCheckbox: true - }, - { - title: 'child2.2', - key: '10022', - children: [ - { - title: 'grandchild2.2.1', - key: '100221', - isLeaf: true - } - ] - } + { title: 'leaf 1-1-0', key: '10020', isLeaf: true } ] - }) - ]; + } ] + } ]; - onChange($event: NzTreeNode): void { + onChange($event: string): void { console.log($event); } ngOnInit(): void { // mock async setTimeout(() => { - this.value = '10001'; + this.value = '1001'; }, 1000); } } diff --git a/components/tree-select/demo/checkable.ts b/components/tree-select/demo/checkable.ts index ef4b2f30b72..4fbb8472a1e 100755 --- a/components/tree-select/demo/checkable.ts +++ b/components/tree-select/demo/checkable.ts @@ -17,68 +17,40 @@ import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; export class NzDemoTreeSelectCheckableComponent implements OnInit { - value: string[] = [ '10001', '10022' ]; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - children: [] - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - } - ] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', - children: [ - { - title : 'child2.1', - key : '10021', - children : [], - disableCheckbox: true - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title : 'grandchild2.2.1', - key : '100221', - isLeaf: true - } - ] - } - ] - }) - ]; + value: string[] = [ '0-0-0' ]; + nodes = [ { + title : 'Node1', + value : '0-0', + key : '0-0', + children: [ { + title : 'Child Node1', + value : '0-0-0', + key : '0-0-0', + isLeaf: true + } ] + }, { + title : 'Node2', + value : '0-1', + key : '0-1', + children: [ { + title : 'Child Node3', + value : '0-1-0', + key : '0-1-0', + isLeaf: true + }, { + title : 'Child Node4', + value : '0-1-1', + key : '0-1-1', + isLeaf: true + }, { + title : 'Child Node5', + value : '0-1-2', + key : '0-1-2', + isLeaf: true + } ] + } ]; - onChange($event: NzTreeNode): void { + onChange($event: string[]): void { console.log($event); } diff --git a/components/tree-select/demo/multiple.ts b/components/tree-select/demo/multiple.ts index 5ec4524bc8a..4cda4262f52 100755 --- a/components/tree-select/demo/multiple.ts +++ b/components/tree-select/demo/multiple.ts @@ -1,85 +1,44 @@ -import {Component, OnInit} from '@angular/core'; -import {NzFormatEmitEvent, NzTreeNode} from 'ng-zorro-antd'; +import { Component, OnInit } from '@angular/core'; +import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-select-multiple', template: ` + [nzNodes]="nodes" + [nzDefaultExpandAll]="true" + [nzAllowClear]="false" + nzPlaceHolder="Please select" + [(ngModel)]="value" + [nzMultiple]="true" + (ngModelChange)="onChange($event)"> ` }) export class NzDemoTreeSelectMultipleComponent implements OnInit { - value: string[] = ['100011']; - nodes = [ - new NzTreeNode({ - title: 'root1', - key: '1001', + value: string[] = []; + nodes = [ { + title : 'parent 1', + key : '100', + children: [ { + title : 'parent 1-0', + key : '1001', children: [ - { - title: 'child1', - key: '10001', - children: [ - { - title: 'child1.1', - key: '100011', - children: [] - }, - { - title: 'child1.2', - key: '100012', - children: [ - { - title: 'grandchild1.2.1', - key: '1000121', - isLeaf: true, - disabled: true - }, - { - title: 'grandchild1.2.2', - key: '1000122', - isLeaf: true - } - ] - } - ] - } + { title: 'leaf 1-0-0', key: '10010', isLeaf: true }, + { title: 'leaf 1-0-1', key: '10011', isLeaf: true } ] - }), - new NzTreeNode({ - title: 'root2', - key: '1002', + }, { + title : 'parent 1-1', + key : '1002', children: [ - { - title: 'child2.1', - key: '10021', - children: [], - disableCheckbox: true - }, - { - title: 'child2.2', - key: '10022', - children: [ - { - title: 'grandchild2.2.1', - key: '100221', - isLeaf: true - } - ] - } + { title: 'leaf 1-1-0', key: '10020', isLeaf: true } ] - }) - ]; + } ] + } ]; - onChange($event: NzTreeNode): void { + onChange($event: string[]): void { console.log($event); } diff --git a/components/tree-select/nz-tree-select.component.html b/components/tree-select/nz-tree-select.component.html index 41efc401ed7..d13dff7ad00 100644 --- a/components/tree-select/nz-tree-select.component.html +++ b/components/tree-select/nz-tree-select.component.html @@ -16,21 +16,20 @@ [ngStyle]="nzDropdownStyle"> + (nzCheckBoxChange)="nzTreeCheckBoxChange.emit($event)"> diff --git a/components/tree-select/nz-tree-select.component.ts b/components/tree-select/nz-tree-select.component.ts index 536b9bd2b71..cc5c84e8dfb 100644 --- a/components/tree-select/nz-tree-select.component.ts +++ b/components/tree-select/nz-tree-select.component.ts @@ -40,7 +40,7 @@ import { filter, tap } from 'rxjs/operators'; import { selectDropDownAnimation } from '../core/animation/select-dropdown-animations'; import { selectTagAnimation } from '../core/animation/select-tag-animations'; import { InputBoolean } from '../core/util/convert'; -import { NzFormatEmitEvent } from '../tree/interface'; +import { NzFormatEmitEvent } from '../tree'; import { NzTreeNode } from '../tree/nz-tree-node'; import { NzTreeComponent } from '../tree/nz-tree.component'; @@ -243,7 +243,7 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, Afte node.isSelected = false; node.isChecked = false; if (this.nzCheckable) { - this.treeRef.nzTreeService.checkTreeNode(node); + this.treeRef.nzTreeService.conduct(node); this.treeRef.nzTreeService.setCheckedNodeList(node); } else { this.treeRef.nzTreeService.setSelectedNodeList(node, this.nzMultiple); @@ -306,7 +306,7 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, Afte const node = event.node; if (this.nzCheckable && !node.isDisabled && !node.isDisableCheckbox) { node.isChecked = !node.isChecked; - this.treeRef.nzTreeService.checkTreeNode(node); + this.treeRef.nzTreeService.conduct(node); this.treeRef.nzTreeService.setCheckedNodeList(node); } if (this.nzCheckable) { @@ -367,8 +367,8 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, Afte } updateDropDownClassMap(): void { - if (this.treeRef && !this.treeRef.classMap[ 'ant-select-tree' ]) { - this.treeRef.classMap = { ...this.treeRef.classMap, [ 'ant-select-tree' ]: true }; + if (this.treeRef && !this.treeRef.nzTreeClass[ 'ant-select-tree' ]) { + this.treeRef.nzTreeClass = { ...this.treeRef.nzTreeClass, [ 'ant-select-tree' ]: true }; } this.dropDownClassMap = { [ 'ant-select-dropdown' ] : true, diff --git a/components/tree-select/nz-tree-select.spec.ts b/components/tree-select/nz-tree-select.spec.ts index 6800b1ae021..891d3647df4 100644 --- a/components/tree-select/nz-tree-select.spec.ts +++ b/components/tree-select/nz-tree-select.spec.ts @@ -1,6 +1,6 @@ import { BACKSPACE } from '@angular/cdk/keycodes'; import { OverlayContainer } from '@angular/cdk/overlay'; -import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; import { async, fakeAsync, flush, inject, tick, TestBed } from '@angular/core/testing'; import { FormsModule, FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; @@ -22,7 +22,7 @@ describe('tree-select component', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports : [ NzTreeSelectModule, NoopAnimationsModule, FormsModule, ReactiveFormsModule ], - declarations: [ NzTestTreeSelectBasicComponent, NzTestTreeSelectCheckableComponent, NzTestTreeSelectFormComponent, NzTestTreeSelectAsyncNodesComponent, NzTestTreeSelectOnPushComponent ] + declarations: [ NzTestTreeSelectBasicComponent, NzTestTreeSelectCheckableComponent, NzTestTreeSelectFormComponent ] }); TestBed.compileComponents(); inject([ OverlayContainer ], (oc: OverlayContainer) => { @@ -35,38 +35,6 @@ describe('tree-select component', () => { overlayContainer.ngOnDestroy(); })); - describe('OnPush', () => { - let fixture; - let testComponent: NzTestTreeSelectOnPushComponent; - let treeSelectComponent: NzTreeSelectComponent; - let treeSelect; - - beforeEach(fakeAsync(() => { - fixture = TestBed.createComponent(NzTestTreeSelectOnPushComponent); - fixture.detectChanges(); - testComponent = fixture.debugElement.componentInstance; - treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent)); - treeSelectComponent = treeSelect.componentInstance; - fixture.detectChanges(); - flush(); - tick(200); - fixture.detectChanges(); - })); - - it('should close when the outside clicks', fakeAsync(() => { - treeSelect.nativeElement.click(); - fixture.detectChanges(); - expect(treeSelectComponent.nzOpen).toBe(true); - tick(200); - expect((overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement).style.opacity).toBe('1'); - dispatchFakeEvent(overlayContainerElement.querySelector('.cdk-overlay-backdrop'), 'click'); - fixture.detectChanges(); - tick(); - expect(treeSelectComponent.nzOpen).toBe(false); - expect((overlayContainerElement.querySelector('.ant-select-dropdown') as HTMLElement).style.opacity).toBe('0'); - })); - }); - describe('basic', () => { let fixture; let testComponent: NzTestTreeSelectBasicComponent; @@ -81,18 +49,19 @@ describe('tree-select component', () => { treeSelectComponent = treeSelect.componentInstance; fixture.detectChanges(); flush(); + fixture.detectChanges(); tick(200); fixture.detectChanges(); })); - it('should size work', () => { + it('should size work', fakeAsync(() => { testComponent.size = 'small'; fixture.detectChanges(); expect(treeSelect.nativeElement.classList).toContain('ant-select-sm'); testComponent.size = 'large'; fixture.detectChanges(); expect(treeSelect.nativeElement.classList).toContain('ant-select-lg'); - }); + })); it('should allowClear work', () => { expect(treeSelect.nativeElement.classList).not.toContain('ant-select-allow-clear'); testComponent.allowClear = true; @@ -164,13 +133,17 @@ describe('tree-select component', () => { it('should set null value work', fakeAsync(() => { fixture.detectChanges(); expect(testComponent.value).toBe('10001'); + testComponent.nzSelectTreeComponent.updateSelectedNodes(); + fixture.detectChanges(); testComponent.setNull(); fixture.detectChanges(); - tick(200); + tick(); + fixture.detectChanges(); + tick(); fixture.detectChanges(); expect(testComponent.value).toBe(null); - expect(treeSelectComponent.selectedNodes.length).toBe(0); - expect(treeSelectComponent.value.length).toBe(0); + expect(testComponent.nzSelectTreeComponent.selectedNodes.length).toEqual(0); + expect(testComponent.nzSelectTreeComponent.value.length).toBe(0); })); it('should dropdown style work', fakeAsync(() => { treeSelect.nativeElement.click(); @@ -185,7 +158,7 @@ describe('tree-select component', () => { fixture.detectChanges(); expect(treeSelectComponent.nzOpen).toBe(true); fixture.detectChanges(); - const targetNode = overlayContainerElement.querySelectorAll('li')[ 2 ]; + const targetNode = overlayContainerElement.querySelectorAll('nz-tree-node')[ 2 ]; dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); flush(); @@ -243,6 +216,7 @@ describe('tree-select component', () => { treeSelectComponent = treeSelect.componentInstance; fixture.detectChanges(); flush(); + fixture.detectChanges(); tick(200); fixture.detectChanges(); })); @@ -282,15 +256,15 @@ describe('tree-select component', () => { it('should set null value work', fakeAsync(() => { fixture.detectChanges(); expect(testComponent.value[ 0 ]).toBe('1000122'); - treeSelectComponent.updateSelectedNodes(); - fixture.detectChanges(); testComponent.setNull(); fixture.detectChanges(); - tick(200); + tick(); + fixture.detectChanges(); + tick(); fixture.detectChanges(); expect(testComponent.value).toBe(null); - expect(treeSelectComponent.selectedNodes.length).toBe(0); - expect(treeSelectComponent.value.length).toBe(0); + expect(testComponent.nzSelectTreeComponent.selectedNodes.length).toBe(0); + expect(testComponent.nzSelectTreeComponent.value.length).toBe(0); })); it('should remove checked when press backs', fakeAsync(() => { @@ -319,7 +293,7 @@ describe('tree-select component', () => { fixture.detectChanges(); expect(treeSelectComponent.nzOpen).toBe(true); fixture.detectChanges(); - const targetNode = overlayContainerElement.querySelectorAll('li')[ 2 ]; + const targetNode = overlayContainerElement.querySelectorAll('nz-tree-node')[ 2 ]; dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); flush(); @@ -366,38 +340,6 @@ describe('tree-select component', () => { })); }); - describe('async nodes', () => { - let fixture; - let testComponent; - let treeSelect; - let treeSelectComponent: NzTreeSelectComponent; - beforeEach(fakeAsync(() => { - fixture = TestBed.createComponent(NzTestTreeSelectAsyncNodesComponent); - fixture.detectChanges(); - testComponent = fixture.debugElement.componentInstance; - treeSelect = fixture.debugElement.query(By.directive(NzTreeSelectComponent)); - treeSelectComponent = treeSelect.componentInstance; - fixture.detectChanges(); - flush(); - tick(200); - fixture.detectChanges(); - })); - it('should update selected nodes after load nodes', fakeAsync(() => { - treeSelectComponent.updateSelectedNodes(); - fixture.detectChanges(); - expect(treeSelectComponent.selectedNodes.length).toBe(0); - testComponent.loadNodes(); - tick(200); - fixture.detectChanges(); - flush(); - fixture.detectChanges(); - treeSelectComponent.updateSelectedNodes(); - fixture.detectChanges(); - expect(treeSelectComponent.selectedNodes.length).toBe(1); - })); - - }); - }); @Component({ @@ -621,107 +563,3 @@ export class NzTestTreeSelectFormComponent { this.formGroup.get('select').reset(null); } } - -@Component({ - selector: 'nz-test-tree-select-async-nodes', - template: ` - - - ` -}) - -export class NzTestTreeSelectAsyncNodesComponent { - value: string = '10001'; - nodes = []; - - loadNodes(): void { - setTimeout(() => { - this.nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - children: [] - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - } - ] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', - children: [ - { - title : 'child2.1', - key : '10021', - children : [], - disableCheckbox: true - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title : 'grandchild2.2.1', - key : '100221', - isLeaf: true - } - ] - } - ] - }) - ]; - }); - } -} - -@Component({ - selector: 'nz-test-tree-select-on-push', - template: ` - - - `, - changeDetection: ChangeDetectionStrategy.OnPush -}) - -export class NzTestTreeSelectOnPushComponent { - value: string = '1001'; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001' - }), - new NzTreeNode({ - title : 'root2', - key : '1002' - }) - ]; -} diff --git a/components/tree/demo/basic-controlled.md b/components/tree/demo/basic-controlled.md new file mode 100644 index 00000000000..d85dd9116db --- /dev/null +++ b/components/tree/demo/basic-controlled.md @@ -0,0 +1,14 @@ +--- +order: 1 +title: + zh-CN: 受控操作示例 + en-US: basic controlled example +--- + +## zh-CN + +受控操作示例(默认)。 + +## en-US + +basic controlled example. diff --git a/components/tree/demo/basic-controlled.ts b/components/tree/demo/basic-controlled.ts new file mode 100644 index 00000000000..c3e73357bd9 --- /dev/null +++ b/components/tree/demo/basic-controlled.ts @@ -0,0 +1,71 @@ +import { Component, OnInit } from '@angular/core'; +import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; + +@Component({ + selector: 'nz-demo-tree-basic-controlled', + template: ` + + + ` +}) + +export class NzDemoTreeBasicControlledComponent implements OnInit { + defaultCheckedKeys = [ '0-0-0' ]; + defaultSelectedKeys = []; + defaultExpandedKeys = [ '0-0', '0-0-0', '0-0-1' ]; + + nodes = [ { + title : '0-0', + key : '0-0', + expanded: true, + children: [ { + title : '0-0-0', + key : '0-0-0', + children: [ + { title: '0-0-0-0', key: '0-0-0-0', isLeaf: true }, + { title: '0-0-0-1', key: '0-0-0-1', isLeaf: true }, + { title: '0-0-0-2', key: '0-0-0-2', isLeaf: true } + ] + }, { + title : '0-0-1', + key : '0-0-1', + children: [ + { title: '0-0-1-0', key: '0-0-1-0', isLeaf: true }, + { title: '0-0-1-1', key: '0-0-1-1', isLeaf: true }, + { title: '0-0-1-2', key: '0-0-1-2', isLeaf: true } + ] + }, { + title : '0-0-2', + key : '0-0-2', + isLeaf: true + } ] + }, { + title : '0-1', + key : '0-1', + children: [ + { title: '0-1-0-0', key: '0-1-0-0', isLeaf: true }, + { title: '0-1-0-1', key: '0-1-0-1', isLeaf: true }, + { title: '0-1-0-2', key: '0-1-0-2', isLeaf: true } + ] + }, { + title : '0-2', + key : '0-2', + isLeaf: true + } ]; + + nzEvent(event: NzFormatEmitEvent): void { + console.log(event); + } + + ngOnInit(): void { + } +} diff --git a/components/tree/demo/basic.md b/components/tree/demo/basic.md index e78d61e15c1..ec62aa3535d 100644 --- a/components/tree/demo/basic.md +++ b/components/tree/demo/basic.md @@ -12,8 +12,3 @@ title: ## en-US The most basic usage, tell you how to use checkable, selectable, disabled, defaultExpandKeys, and etc. - - - diff --git a/components/tree/demo/basic.ts b/components/tree/demo/basic.ts index d492b9d89be..c4848a07636 100644 --- a/components/tree/demo/basic.ts +++ b/components/tree/demo/basic.ts @@ -1,74 +1,61 @@ -import { Component, OnInit } from '@angular/core'; -import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-basic', template: ` - ` + #treeCom + [nzData]="nodes" + nzCheckable="true" + nzMultiple="true" + [nzCheckedKeys]="defaultCheckedKeys" + [nzExpandedKeys]="defaultExpandedKeys" + [nzSelectedKeys]="defaultSelectedKeys" + (nzClick)="nzClick($event)" + (nzCheckBoxChange)="nzCheck($event)"> + + ` }) export class NzDemoTreeBasicComponent implements OnInit { - expandKeys = [ '1001', '10001' ]; - checkedKeys = [ '100011', '1002' ]; - selectedKeys = [ '10001', '100011' ]; - expandDefault = false; - nodes = [ - new NzTreeNode({ - title : 'root1', + @ViewChild('treeCom') treeCom; + defaultCheckedKeys = [ '1001', '1002' ]; + defaultSelectedKeys = [ '10011' ]; + defaultExpandedKeys = [ '100', '1001' ]; + + nodes: NzTreeNodeOptions[] = [ { + title : 'parent 1', + key : '100', + children: [ { + title : 'parent 1-0', key : '1001', + disabled: true, + children: [ + { title: 'leaf 1-0-0', key: '10010', disableCheckbox: true, isLeaf: true }, + { title: 'leaf 1-0-1', key: '10011', isLeaf: true, checked: true } + ] + }, { + title : 'parent 1-1', + key : '1002', children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - isLeaf: true - }, - { - title : 'child1.2', - key : '100012', - isLeaf: true - } - ] - }, - { - title : 'child2', - key : '10002', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } + { title: 'leaf 1-1-0', key: '10020', isLeaf: true } ] - }) - ]; + } ] + } ]; - mouseAction(name: string, event: NzFormatEmitEvent): void { - console.log(name, event); + nzClick(event: NzFormatEmitEvent): void { + console.log(event, event.selectedKeys, event.keys, event.nodes); + } + + nzCheck(event: NzFormatEmitEvent): void { + console.log(event, event.checkedKeys, event.keys, event.nodes); } ngOnInit(): void { + setTimeout(() => { + console.log(this.treeCom.nzTreeService, this.treeCom.getCheckedNodeList()); + }, 500); + } } diff --git a/components/tree/demo/customized-icon.md b/components/tree/demo/customized-icon.md index 96d29a43b48..3b7b6385a2c 100644 --- a/components/tree/demo/customized-icon.md +++ b/components/tree/demo/customized-icon.md @@ -1,15 +1,14 @@ --- -order: 4 -debug: true +order: 7 title: zh-CN: 自定义图标 - en-US: customize + en-US: Customize Icon --- ## zh-CN -可以针对不同节点采用样式覆盖的方式定制图标,双击展开。 +可以针对不同的节点定制图标。 ## en-US -You can customize icons for different nodes by styles override and expand the node using dblclick. +You can customize icons for different nodes. diff --git a/components/tree/demo/customized-icon.ts b/components/tree/demo/customized-icon.ts index f5e5c2d3e37..94c092c1e45 100644 --- a/components/tree/demo/customized-icon.ts +++ b/components/tree/demo/customized-icon.ts @@ -1,102 +1,30 @@ import { Component, OnInit } from '@angular/core'; -import { NzTreeNode } from 'ng-zorro-antd'; +import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-customized-icon', template: ` - - - - - - {{node.title}} - - - - `, - styles : [ ` - :host ::ng-deep .ant-tree { - overflow: hidden; - margin: 0 -24px; - padding: 0 24px; - } - - .custom-node { - cursor: pointer; - line-height: 30px; - display: inline-block; - margin: 0 -1000px; - padding: 0 1000px; - } - - .active { - background: #1890ff; - color: #fff; - } - - .anticon { - padding: 0 4px; - } - ` ] + + + ` }) + export class NzDemoTreeCustomizedIconComponent implements OnInit { nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', + { + title : 'parent 1', + key : '100', expanded: true, + icon : 'anticon anticon-smile-o', children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - selected: true, - children: [] - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - checked : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - } + { title: 'leaf', key: '1001', icon: 'anticon anticon-meh-o', isLeaf: true }, + { title: 'leaf', key: '1002', icon: 'anticon anticon-frown-o', isLeaf: true } ] - }) - ]; - - mouseAction(name: string, e: any): void { - switch (name) { - case 'click': - break; - case 'dblclick': - setTimeout(() => { - e.node.isExpanded = !e.node.isExpanded; - }); - break; } - } + ]; ngOnInit(): void { - } } diff --git a/components/tree/demo/dir-tree.md b/components/tree/demo/dir-tree.md deleted file mode 100644 index 55b54c15feb..00000000000 --- a/components/tree/demo/dir-tree.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -order: 5 -title: - zh-CN: 文件树 - en-US: directory tree ---- - -## zh-CN - -自定义Tree组件实现文件树,点击图标展开文件夹,鼠标拖拽。右键自定义菜单。 - -## en-US - -Built-in directory tree with tree component, click icon to open the folder and dnd.Trigger dropdown with contextmenu. \ No newline at end of file diff --git a/components/tree/demo/dir-tree.ts b/components/tree/demo/dir-tree.ts deleted file mode 100644 index 43b728aedd7..00000000000 --- a/components/tree/demo/dir-tree.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { Component, HostListener, OnInit, TemplateRef } from '@angular/core'; -import { NzDropdownService, NzFormatEmitEvent, NzTreeNode, NzDropdownContextComponent } from 'ng-zorro-antd'; - -@Component({ - selector: 'nz-demo-tree-dir-tree', - template: ` - - -
    -
  • 新建文件
  • -
  • 新建文件夹
  • -
-
- - - - - - {{node.title}} - {{node?.origin?.author | lowercase}} created at 2018-04-01 - - - - {{node.title}} - {{node?.origin?.author | lowercase}} modified at 2018-05-01 - - - -
`, - styles : [ ` - :host ::ng-deep .ant-tree { - overflow: hidden; - margin: 0 -24px; - padding: 0 24px; - } - - :host ::ng-deep .ant-tree li { - padding: 4px 0 0 0; - } - - @keyframes shine { - 0% { - opacity: 1; - } - 50% { - opacity: 0.5; - } - 100% { - opacity: 1; - } - } - - .shine-animate { - animation: shine 2s ease infinite; - } - - .custom-node { - cursor: pointer; - line-height: 26px; - margin-left: 4px; - display: inline-block; - margin: 0 -1000px; - padding: 0 1000px; - } - - .active { - background: #1890FF; - color: #fff; - } - - .is-dragging { - background-color: transparent !important; - color: #000; - opacity: 0.7; - } - - .file-name, .folder-name, .file-desc, .folder-desc { - margin-left: 4px; - } - - .file-desc, .folder-desc { - padding: 2px 8px; - background: #87CEFF; - color: #FFFFFF; - } - ` ] -}) -export class NzDemoTreeDirTreeComponent implements OnInit { - dropdown: NzDropdownContextComponent; - // can active only one node - activedNode: NzTreeNode; - dragNodeElement; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - author : 'ANGULAR', - expanded: true, - children: [ - { - title : 'child1', - key : '10001', - author : 'ZORRO', - children: [ - { - title : 'child1.1', - key : '100011', - author : 'ZORRO', - children: [] - }, - { - title : 'child1.2', - key : '100012', - author : 'ZORRO', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - author : 'ZORRO-FANS', - isLeaf : true, - checked : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - author: 'ZORRO-FANS', - isLeaf: true - } - ] - } - ] - } - ] - }) - ]; - - @HostListener('mouseleave', [ '$event' ]) - mouseLeave(event: MouseEvent): void { - event.preventDefault(); - if (this.dragNodeElement && this.dragNodeElement.className.indexOf('is-dragging') > -1) { - this.dragNodeElement.className = this.dragNodeElement.className.replace(' is-dragging', ''); - } - } - - @HostListener('mousedown') - mouseDown(): void { - // do not prevent - if (this.dragNodeElement && this.dragNodeElement.className.indexOf('is-dragging') > -1) { - this.dragNodeElement.className = this.dragNodeElement.className.replace(' is-dragging', ''); - } - } - - /** - * important: - * if u want to custom event/node properties, u need to maintain the selectedNodesList/checkedNodesList yourself - * @param {} data - */ - openFolder(data: NzTreeNode | NzFormatEmitEvent): void { - // do something if u want - if (data instanceof NzTreeNode) { - // change node's expand status - if (!data.isExpanded) { - // close to open - data.origin.isLoading = true; - setTimeout(() => { - data.isExpanded = !data.isExpanded; - data.origin.isLoading = false; - }, 500); - } else { - data.isExpanded = !data.isExpanded; - } - } else { - // change node's expand status - if (!data.node.isExpanded) { - // close to open - data.node.origin.isLoading = true; - setTimeout(() => { - data.node.isExpanded = !data.node.isExpanded; - data.node.origin.isLoading = false; - }, 500); - } else { - data.node.isExpanded = !data.node.isExpanded; - } - } - } - - // 选中节点 - activeNode(data: NzFormatEmitEvent): void { - if (this.activedNode) { - this.activedNode = null; - } - data.node.isSelected = true; - this.activedNode = data.node; - } - - dragStart(event: NzFormatEmitEvent): void { - // disallow drag if root or search - this.activedNode = null; - this.dragNodeElement = event.event.srcElement; - if (this.dragNodeElement.className.indexOf('is-dragging') === -1) { - this.dragNodeElement.className = event.event.srcElement.className + ' is-dragging'; - } - } - - contextMenu($event: MouseEvent, template: TemplateRef, node: NzTreeNode): void { - this.dropdown = this.nzDropdownService.create($event, template); - } - - selectDropdown(): void { - this.dropdown.close(); - // do something - console.log('dropdown clicked'); - } - - constructor(private nzDropdownService: NzDropdownService) { - } - - ngOnInit(): void { - - } -} diff --git a/components/tree/demo/directory.md b/components/tree/demo/directory.md new file mode 100644 index 00000000000..c42b600b01d --- /dev/null +++ b/components/tree/demo/directory.md @@ -0,0 +1,14 @@ +--- +order: 8 +title: + zh-CN: 目录 + en-US: directory +--- + +## zh-CN + +自定义目录树(使用nzTreeTemplate实现,支持右键)。 + +## en-US + +Customize directory tree(with nzTreeTemplate, supported contextmenu). diff --git a/components/tree/demo/directory.ts b/components/tree/demo/directory.ts new file mode 100644 index 00000000000..9ac98be6167 --- /dev/null +++ b/components/tree/demo/directory.ts @@ -0,0 +1,135 @@ +import { Component, TemplateRef, ViewChild } from '@angular/core'; +import { + NzDropdownContextComponent, + NzDropdownService, + NzFormatEmitEvent, + NzTreeComponent, + NzTreeNode +} from 'ng-zorro-antd'; + +@Component({ + selector: 'nz-demo-tree-directory', + template: ` + + +
    +
  • 新建文件
  • +
  • 新建文件夹
  • +
+
+ + + + + {{node.title}} + created by {{node?.origin?.author | lowercase}} + + + + {{node.title}} + modified by {{node?.origin?.author | lowercase}} + + + +
`, + styles : [ ` + :host ::ng-deep .ant-tree { + overflow: hidden; + margin: 0 -24px; + padding: 0 24px; + } + + :host ::ng-deep .ant-tree li { + padding: 4px 0 0 0; + } + + .custom-node { + cursor: pointer; + line-height: 24px; + margin-left: 4px; + display: inline-block; + margin: 0 -1000px; + padding: 0 1000px; + } + + .active { + background: #1890FF; + color: #fff; + } + + .file-name, .folder-name { + margin-left: 4px; + } + + .file-desc, .folder-desc { + padding: 0 8px; + display: inline-block; + background: #87CEFF; + color: #FFFFFF; + position: relative; + left: 12px; + } + ` ] +}) + +export class NzDemoTreeDirectoryComponent { + @ViewChild('treeCom') treeCom: NzTreeComponent; + dropdown: NzDropdownContextComponent; + // actived node + activedNode: NzTreeNode; + nodes = [ { + title : 'parent 0', + key : '100', + author : 'NG ZORRO', + expanded: true, + children: [ + { title: 'leaf 0-0', key: '1000', author: 'NG ZORRO', isLeaf: true }, + { title: 'leaf 0-1', key: '1001', author: 'NG ZORRO', isLeaf: true } + ] + }, { + title : 'parent 1', + key : '101', + author : 'NG ZORRO', + children: [ + { title: 'leaf 1-0', key: '1010', author: 'NG ZORRO', isLeaf: true }, + { title: 'leaf 1-1', key: '1011', author: 'NG ZORRO', isLeaf: true } + ] + } ]; + + openFolder(data: NzTreeNode | NzFormatEmitEvent): void { + // do something if u want + if (data instanceof NzTreeNode) { + data.isExpanded = !data.isExpanded; + } else { + data.node.isExpanded = !data.node.isExpanded; + } + } + + activeNode(data: NzFormatEmitEvent): void { + if (this.activedNode) { + // delete selectedNodeList(u can do anything u want) + this.treeCom.nzTreeService.setSelectedNodeList(this.activedNode); + } + data.node.isSelected = true; + this.activedNode = data.node; + // add selectedNodeList + this.treeCom.nzTreeService.setSelectedNodeList(this.activedNode); + } + + contextMenu($event: MouseEvent, template: TemplateRef): void { + this.dropdown = this.nzDropdownService.create($event, template); + } + + selectDropdown(type: string): void { + this.dropdown.close(); + // do something + } + + constructor(private nzDropdownService: NzDropdownService) { + } +} diff --git a/components/tree/demo/draggable-confirm.md b/components/tree/demo/draggable-confirm.md index 93898c73c92..b47ab3bd9f0 100644 --- a/components/tree/demo/draggable-confirm.md +++ b/components/tree/demo/draggable-confirm.md @@ -7,8 +7,8 @@ title: ## zh-CN -nzBeforeDrop: 在拖拽放置事件(drop事件)之前做校验, 例如仅允许拖拽到内部(延时一秒)。 +nzBeforeDrop: 在拖拽放置事件(drop事件)之前做校验, 例如仅允许拖拽到内部(延时一秒)、放置前结合modal验证等。 ## en-US -nzBeforeDrop: Validate before drop event, for example only allowed to drag inside(delay 1s). +nzBeforeDrop: Validate before drop event, for example: only allow to drag inside(delay 1s)、 validate using modal .etc. \ No newline at end of file diff --git a/components/tree/demo/draggable-confirm.ts b/components/tree/demo/draggable-confirm.ts index bff85b99fd1..215ca0d1276 100644 --- a/components/tree/demo/draggable-confirm.ts +++ b/components/tree/demo/draggable-confirm.ts @@ -1,100 +1,48 @@ -import { Component } from '@angular/core'; -import { NzFormatBeforeDropEvent, NzFormatEmitEvent, NzModalService, NzTreeNode } from 'ng-zorro-antd'; +import { Component, OnInit } from '@angular/core'; +import { NzFormatBeforeDropEvent, NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; import { of, Observable } from 'rxjs'; import { delay } from 'rxjs/operators'; @Component({ selector: 'nz-demo-tree-draggable-confirm', template: ` - + (nzOnDragStart)="nzAction($event)" + (nzOnDragEnter)="nzAction($event)" + (nzOnDragLeave)="nzAction($event)" + (nzOnDrop)="nzAction($event)" + (nzOnDragEnd)="nzAction($event)"> - `, - styles : [ - ` - :host ::ng-deep .ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected { - width: calc(100% - 8px); - } - - :host ::ng-deep .ant-tree li span[draggable], :host ::ng-deep .ant-tree li span[draggable="true"] { - width: calc(100% - 8px); - } - ` - ] + ` }) -export class NzDemoTreeDraggableConfirmComponent { - nodes = [ - new NzTreeNode({ - title : 'root1', +export class NzDemoTreeDraggableConfirmComponent implements OnInit { + nodes = [ { + title : '0-0', + key : '100', + expanded: true, + children: [ { + title : '0-0-0', key : '1001', children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - isLeaf: true - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - checked : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - } + { title: '0-0-0-0', key: '10010', isLeaf: true }, + { title: '0-0-0-1', key: '10011', isLeaf: true } ] - }), - new NzTreeNode({ - title : 'root2', + }, { + title : '0-0-1', key : '1002', children: [ - { - title : 'child2.1', - key : '10021', - isLeaf: true - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title : 'grandchild2.2.1', - key : '100221', - isLeaf: true - } - ] - } + { title: '0-0-1-0', key: '10020', isLeaf: true } ] - }) - ]; + } ] + } ]; - mouseAction(name: string, e: NzFormatEmitEvent): void { - if (name !== 'over') { - console.log(name, e); - } + nzAction(event: NzFormatEmitEvent): void { + console.log(event); } beforeDrop(arg: NzFormatBeforeDropEvent): Observable { @@ -105,4 +53,7 @@ export class NzDemoTreeDraggableConfirmComponent { return of(false); } } + + ngOnInit(): void { + } } diff --git a/components/tree/demo/draggable.ts b/components/tree/demo/draggable.ts index 8b636dd33d8..f368066f79a 100644 --- a/components/tree/demo/draggable.ts +++ b/components/tree/demo/draggable.ts @@ -4,93 +4,77 @@ import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-draggable', template: ` - - `, + + + `, styles : [ ` - :host ::ng-deep .ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected { - width: calc(100% - 8px); - } - - :host ::ng-deep .ant-tree li span[draggable], :host ::ng-deep .ant-tree li span[draggable="true"] { - width: calc(100% - 8px); + :host ::ng-deep .draggable-tree .ant-tree-node-content-wrapper { + width: calc(100% - 42px); } ` ] }) + export class NzDemoTreeDraggableComponent implements OnInit { - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', + nodes = [ { + title : '0-0', + key : '00', + expanded: true, + children: [ { + title : '0-0-0', + key : '000', + expanded: true, children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - isLeaf: true - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - checked : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - } + { title: '0-0-0-0', key: '0000', isLeaf: true }, + { title: '0-0-0-1', key: '0001', isLeaf: true }, + { title: '0-0-0-2', key: '0002', isLeaf: true } ] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', + }, { + title : '0-0-1', + key : '001', children: [ - { - title : 'child2.1', - key : '10021', - isLeaf: true - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title : 'grandchild2.2.1', - key : '100221', - isLeaf: true - } - ] - } + { title: '0-0-1-0', key: '0010', isLeaf: true }, + { title: '0-0-1-1', key: '0011', isLeaf: true }, + { title: '0-0-1-2', key: '0012', isLeaf: true } ] - }) - ]; - - mouseAction(name: string, e: NzFormatEmitEvent): void { - if (name !== 'over') { - console.log(name, e); - } - } + }, { + title: '0-0-2', + key : '002' + } ] + }, { + title : '0-1', + key : '01', + children: [ { + title : '0-1-0', + key : '010', + children: [ + { title: '0-1-0-0', key: '0100', isLeaf: true }, + { title: '0-1-0-1', key: '0101', isLeaf: true }, + { title: '0-1-0-2', key: '0102', isLeaf: true } + ] + }, { + title : '0-1-1', + key : '011', + children: [ + { title: '0-1-1-0', key: '0110', isLeaf: true }, + { title: '0-1-1-1', key: '0111', isLeaf: true }, + { title: '0-1-1-2', key: '0112', isLeaf: true } + ] + } ] + }, { + title : '0-2', + key : '02', + isLeaf: true + } ]; - constructor() { + nzEvent(event: NzFormatEmitEvent): void { + console.log(event); } ngOnInit(): void { diff --git a/components/tree/demo/dynamic.md b/components/tree/demo/dynamic.md index f8b7984cb65..c68eb33697c 100644 --- a/components/tree/demo/dynamic.md +++ b/components/tree/demo/dynamic.md @@ -1,5 +1,5 @@ --- -order: 7 +order: 4 title: zh-CN: 异步数据加载 en-US: load data asynchronously @@ -7,8 +7,8 @@ title: ## zh-CN -点击展开节点,动态加载数据,直到执行 addChildren() 方法取消加载状态。 +点击展开节点,动态加载数据。 ## en-US -To load data asynchronously when click to expand a treeNode, loading state keeps until excute addChildren(). +To load data asynchronously when click to expand a treeNode. diff --git a/components/tree/demo/dynamic.ts b/components/tree/demo/dynamic.ts index afa58b3c6d1..e9bf67263e6 100644 --- a/components/tree/demo/dynamic.ts +++ b/components/tree/demo/dynamic.ts @@ -1,48 +1,39 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-dynamic', template: ` - - ` + + + ` }) -export class NzDemoTreeDynamicComponent { + +export class NzDemoTreeDynamicComponent implements OnInit { nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - children: [] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', - children: [] - }), - new NzTreeNode({ - title: 'root3', - key : '1003' - }) + { title: 'Expand to load', key: '0' }, + { title: 'Expand to load', key: '1' }, + { title: 'Tree Node', key: '2', isLeaf: true } ]; - mouseAction(name: string, e: NzFormatEmitEvent): void { - if (name === 'expand') { + nzEvent(event: NzFormatEmitEvent): void { + console.log(event); + // load child async + if (event.eventName === 'expand') { setTimeout(_ => { - if (e.node.getChildren().length === 0 && e.node.isExpanded) { - e.node.addChildren([ - { - title: 'childAdd-1', - key : '10031-' + (new Date()).getTime() - }, - { - title : 'childAdd-2', - key : '10032-' + (new Date()).getTime(), - isLeaf: true - } ]); + if (event.node.getChildren().length === 0 && event.node.isExpanded) { + event.node.addChildren([ + { title: 'Child Node', key: `${event.node.key}-0` }, + { title: 'Child Node', key: `${event.node.key}-1` } ]); } }, 1000); } } + + ngOnInit(): void { + } } diff --git a/components/tree/demo/line.md b/components/tree/demo/line.md index b777e858f15..33f6dde4d02 100644 --- a/components/tree/demo/line.md +++ b/components/tree/demo/line.md @@ -1,8 +1,8 @@ --- -order: 1 +order: 6 title: zh-CN: 连接线 - en-US: tree with line + en-US: Tree With Line --- ## zh-CN @@ -11,4 +11,4 @@ title: ## en-US -Tree With Line +Tree With Line. diff --git a/components/tree/demo/line.ts b/components/tree/demo/line.ts index 26a9a1b199e..cbe34b7a74e 100644 --- a/components/tree/demo/line.ts +++ b/components/tree/demo/line.ts @@ -1,92 +1,51 @@ -import { Component } from '@angular/core'; -import { NzTreeNode } from 'ng-zorro-antd'; +import { Component, OnInit } from '@angular/core'; +import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-line', template: ` - - ` + + + ` }) -export class NzDemoTreeLineComponent { - expandKeys = [ '1001', '10001' ]; - nodes = [ - new NzTreeNode({ - title : 'root1', + +export class NzDemoTreeLineComponent implements OnInit { + nodes = [ { + title : 'parent 1', + key : '100', + expanded: true, + children: [ { + title : 'parent 1-0', key : '1001', + expanded: true, children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - }, - { - title : 'child2', - key : '10002', - children: [ - { - title : 'grandchild2.1', - key : '1000122', - isLeaf: true - }, - { - title : 'grandchild2.2', - key : '1000123', - isLeaf: true - } - ] - } + { title: 'leaf', key: '10010', isLeaf: true }, + { title: 'leaf', key: '10011', isLeaf: true }, + { title: 'leaf', key: '10012', isLeaf: true } ] - }), - new NzTreeNode({ - title : 'root2', + }, { + title : 'parent 1-1', key : '1002', children: [ - { - title : 'child2.1', - key : '10021', - children : [], - disableCheckbox: true - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title : 'grandchild2.2.1', - key : '100221', - isLeaf: true - } - ] - } + { title: 'leaf', key: '10020', isLeaf: true } + ] + }, { + title : 'parent 1-2', + key : '1003', + children: [ + { title: 'leaf', key: '10030', isLeaf: true }, + { title: 'leaf', key: '10031', isLeaf: true } ] - }) - ]; + } ] + } ]; + + nzEvent(event: NzFormatEmitEvent): void { + console.log(event); + } - mouseAction(name: string, e: any): void { - console.log(name, e); + ngOnInit(): void { } } diff --git a/components/tree/demo/method.md b/components/tree/demo/method.md deleted file mode 100644 index 8a0a6bcebb0..00000000000 --- a/components/tree/demo/method.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -order: 8 -title: - zh-CN: 常用方法 - en-US: common methods ---- - -## zh-CN - -Tree组件通过几种常用方法供用户快速获取数据。 - -## en-US - -Tree components provide quick access to data through several common methods. \ No newline at end of file diff --git a/components/tree/demo/method.ts b/components/tree/demo/method.ts deleted file mode 100644 index 27239522da3..00000000000 --- a/components/tree/demo/method.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { NzFormatEmitEvent, NzTreeComponent, NzTreeNode } from 'ng-zorro-antd'; - -@Component({ - selector: 'nz-demo-tree-method', - template: ` - - ` -}) - -export class NzDemoTreeMethodComponent implements OnInit { - @ViewChild('nzTree') nzTree: NzTreeComponent; - expandKeys = [ '1001', '10001' ]; - checkedKeys = [ '10001' ]; - selectedKeys = [ '10001', '100011' ]; - expandDefault = false; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - children: [] - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - } - ] - }) - ]; - - mouseAction(name: string, event: NzFormatEmitEvent): void { - console.log(name, event); - // just for demo, should get in ngAfterViewInit - console.log('checkedNodes: %o', this.nzTree.getCheckedNodeList()); - console.log('selectedNodes: %o', this.nzTree.getSelectedNodeList()); - console.log('halfCheckedNodes: %o', this.nzTree.getHalfCheckedNodeList()); - console.log(this.nzTree.nzTreeService.getCheckedNodeList()); - } - - ngOnInit(): void { - } -} diff --git a/components/tree/demo/search.md b/components/tree/demo/search.md index 6109df1583d..9a7ccd592c0 100644 --- a/components/tree/demo/search.md +++ b/components/tree/demo/search.md @@ -1,8 +1,8 @@ --- -order: 6 +order: 5 title: zh-CN: 可搜索 - en-US: searchable + en-US: Searchable --- ## zh-CN @@ -11,4 +11,4 @@ title: ## en-US -Searchable Tree. +Searchable Tree. \ No newline at end of file diff --git a/components/tree/demo/search.ts b/components/tree/demo/search.ts index a2471204994..c1ff2ff0ba9 100644 --- a/components/tree/demo/search.ts +++ b/components/tree/demo/search.ts @@ -1,88 +1,77 @@ -import { Component } from '@angular/core'; -import { NzTreeNode } from 'ng-zorro-antd'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { NzFormatEmitEvent, NzTreeNode } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-search', template: ` - + - - ` + + + `, + styles : [ ` + nz-input-group { + padding: 10px 0; + } + ` ] }) -export class NzDemoTreeSearchComponent { + +export class NzDemoTreeSearchComponent implements OnInit { + @ViewChild('treeCom') treeCom; searchValue; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', + + nodes = [ { + title : '0-0', + key : '0-0', + children: [ { + title : '0-0-0', + key : '0-0-0', children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - children: [] - }, - { - title : 'child1.2', - key : '100012', - checked : true, - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf: true - } - ] - } - ] - }, - { - title : 'child2', - key : '10002', - isLeaf: true - } + { title: '0-0-0-0', key: '0-0-0-0', isLeaf: true }, + { title: '0-0-0-1', key: '0-0-0-1', isLeaf: true }, + { title: '0-0-0-2', key: '0-0-0-2', isLeaf: true } ] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', + }, { + title : '0-0-1', + key : '0-0-1', children: [ - { - title : 'child2.1', - key : '10021', - children: [] - }, - { - title : 'child1.2', - key : '10022', - selectable: false, - children : [ - { - title : 'grandchild2.2.1', - key : '100221', - isLeaf: true - } - ] - } + { title: '0-0-1-0', key: '0-0-1-0', isLeaf: true }, + { title: '0-0-1-1', key: '0-0-1-1', isLeaf: true }, + { title: '0-0-1-2', key: '0-0-1-2', isLeaf: true } ] - }) - ]; + }, { + title : '0-0-2', + key : '0-0-2', + isLeaf: true + } ] + }, { + title : '0-1', + key : '0-1', + children: [ + { title: '0-1-0-0', key: '0-1-0-0', isLeaf: true }, + { title: '0-1-0-1', key: '0-1-0-1', isLeaf: true }, + { title: '0-1-0-2', key: '0-1-0-2', isLeaf: true } + ] + }, { + title : '0-2', + key : '0-2', + isLeaf: true + } ]; + + nzEvent(event: NzFormatEmitEvent): void { + console.log(event, this.treeCom.getMatchedNodeList().map(v => v.title)); + } - mouseAction(name: string, e: any): void { - console.log(name, e); + ngOnInit(): void { } } diff --git a/components/tree/doc/index.en-US.md b/components/tree/doc/index.en-US.md index 710a948e741..95bf33eeca2 100644 --- a/components/tree/doc/index.en-US.md +++ b/components/tree/doc/index.en-US.md @@ -14,7 +14,12 @@ Almost anything can be represented in a tree structure. Examples include directo | Property | Description | Type | Default | | -------- | ----------- | ---- | ------- | -| `[ngModel]` | Tree data (Reference NzTreeNode) | NzTreeNode\[] | \[] | +| `[ngModel]` | Tree data `Deprecated` | NzTreeNode[] | \[] | +| `[nzDefaultExpandAll]` | Whether to expand all treeNodes `Deprecated` | boolean | false | +| `[nzDefaultExpandedKeys]` | Specify the keys of the default expanded treeNodes `Deprecated` | string\[] | \[] | +| `[nzDefaultCheckedKeys]` | Specifies the keys of the default checked treeNodes `Deprecated` | string\[] | \[] | +| `[nzDefaultSelectedKeys]` | Specifies the keys of the default selected treeNodes `Deprecated` | string\[] | \[] | +| `[nzData]` | Tree data (Reference NzTreeNode) | NzTreeNode\[] | \[] | | `[nzCheckable]` | Adds a Checkbox before the treeNodes| boolean | false | | `[nzShowExpand]` | Show a Expand Icon before the treeNodes | boolean | true | | `[nzShowLine]` | Shows a connecting line | boolean | false | @@ -22,10 +27,10 @@ Almost anything can be represented in a tree structure. Examples include directo | `[nzDraggable]` | Specifies whether this Tree is draggable (IE > 8) | boolean | false | | `[nzMultiple]` | Allows selecting multiple treeNodes | boolean | false | | `[nzCheckStrictly]` | Check treeNode precisely; parent treeNode and children treeNodes are not associated | boolean | false | -| `[nzDefaultExpandAll]` | Whether to expand all treeNodes by default | boolean | false | -| `[nzDefaultExpandedKeys]` | Specify the keys of the default expanded treeNodes | string\[] | \[] | -| `[nzDefaultCheckedKeys]` | Specifies the keys of the default checked treeNodes | string\[] | \[] | -| `[nzDefaultSelectedKeys]` | Specifies the keys of the default selected treeNodes(set nzMultiple to be true) | string\[] | \[] | +| `[nzExpandAll]` | Whether to expand all treeNodes | boolean | false | +| `[nzExpandedKeys]` | Specify the keys of the default expanded treeNodes | string\[] | \[] | +| `[nzCheckedKeys]` | Specifies the keys of the default checked treeNodes | string\[] | \[] | +| `[nzSelectedKeys]` | Specifies the keys of the default selected treeNodes(set nzMultiple to be true) | string\[] | \[] | | `[nzSearchValue]` | Filter (highlight) treeNodes (see demo `Searchable`) | string | null | | `[nzBeforeDrop]` | Drop before the second check, allowing the user to decide whether to allow placement | `(confirm: NzFormatBeforeDropEvent) => Observable` | - | | `(nzClick)` | Callback function for when the user clicks a treeNode | EventEmitter | - | @@ -33,7 +38,7 @@ Almost anything can be represented in a tree structure. Examples include directo | `(nzContextMenu)` | Callback function for when the user right clicks a treeNode | EventEmitter | - | | `(nzCheckBoxChange)` | Callback function for when user clicks the Checkbox | EventEmitter | - | | `(nzExpandChange)` | Callback function for when a treeNode is expanded or collapsed |EventEmitter | - | -| `(nzOnSearchNode)` | Callback function for when filter treeNodes(used with nzSearchValue) | EventEmitter | - | +| `(nzSearchValueChange)` | Callback function for when filter treeNodes(used with nzSearchValue) | EventEmitter | - | | `(nzOnDragStart)` | Callback function for when the onDragStart event occurs | EventEmitter | - | | `(nzOnDragEnter)` | Callback function for when the onDragEnter event occurs | EventEmitter | - | | `(nzOnDragOver)` | Callback function for when the onDragOver event occurs | EventEmitter | - | @@ -48,14 +53,16 @@ Almost anything can be represented in a tree structure. Examples include directo | getCheckedNodeList | get checked nodes(merged) | NzTreeNode[] | [] | | getSelectedNodeList | get selected nodes | NzTreeNode[] | [] | | getHalfCheckedNodeList | get half checked nodes | NzTreeNode[] | [] | +| getExpandedNodeList | get expanded nodes | NzTreeNode[] | [] | +| getMatchedNodeList | get matched nodes(if nzSearchValue is not null) | NzTreeNode[] | [] | #### NzTreeNodeOptions props | Property | Description | Type | Default | | --- | --- | --- | --- | | title | Title | string | '---' | -| key | Used with nzDefaultExpandedKeys / nzDefaultCheckedKeys / nzDefaultSelectedKeys. P.S.: It must be unique in all of treeNodes of the tree!| string | null | -| children | treeNode's children | array | \[] | +| key | Must be unique!| string | null | +| children | TreeNode's children | NzTreeNodeOptions[] | \[] | | isLeaf | Determines if this is a leaf node(can not be dropped to) | boolean | false | | checked | Set the treeNode be checked | boolean | false | | selected | Set the treeNode be selected | boolean | false | @@ -71,11 +78,12 @@ Almost anything can be represented in a tree structure. Examples include directo | eventName | Event Name | enum: `click` `dblclick` `contextmenu` `check` `expand` `search` & `dragstart` `dragenter` `dragover` `dragleave` `drop` `dragend` | '' | | node | The current operation node (such as the target node to drop while dragging) | NzTreeNode | null | | event | MouseEvent or DragEvent | enum: `MouseEvent` `DragEvent` | null | -| dragNode? | Current drag node (existing when dragged) | NzTreeNode | null | -| selectedKeys? | Selected node list (exist when clicked) | array | [] | -| checkedKeys? | Checked node list (exist when click checkbox) | array | [] | -| flatCheckedKeys? | Flatten the Checked nodes list (exist when click checkbox) | array | [] | -| matchededKeys? | matched nodes while searching | array | [] | +| dragNode? | Current drag node (existing if dragged) | NzTreeNode | null | +| selectedKeys? | Selected nodes list | NzTreeNode[] | [] | +| checkedKeys? | Checked nodes list | NzTreeNode[] | [] | +| matchedKeys? | Matched keys list while searching | NzTreeNode[] | [] | +| keys? | All nodes's keys list related event(except drag events) | string[] | [] | +| nodes? | All nodes related event(except drag events) | NzTreeNode[] | [] | #### NzFormatBeforeDropEvent props @@ -108,7 +116,9 @@ Almost anything can be represented in a tree structure. Examples include directo | isMatched | Whether treeNode's title contains nzSearchValue | boolean | `true` / `false` | | getChildren | Get all children | function | NzTreeNode[] | | addChildren | Add child nodes, receive NzTreeNode or NzTreeNodeOptions array, the second parameter is the inserted index position | (children: array, index?: number )=>{} | void | -| clearChildren | clear the treeNode's children | function | void | +| setChecked | set isChecked & isHalfChecked state,params: checked , halfChecked | (checked: boolean, halfChecked: boolean=false)=>{} | void | +| setExpanded | set isExpanded state | (value: boolean)=>{} | void | +| setSelected | set isSelected state | (value: boolean)=>{} | void | ## Note `NzTreeNodeOptions` accepts your customized properties,use NzTreeNode.origin to get them. diff --git a/components/tree/doc/index.zh-CN.md b/components/tree/doc/index.zh-CN.md index b55d21f657a..ee3927c03fc 100644 --- a/components/tree/doc/index.zh-CN.md +++ b/components/tree/doc/index.zh-CN.md @@ -15,7 +15,12 @@ subtitle: 树形控件 | 参数 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| `[ngModel]` | 元数据,NzTreeNode数组,单个节点原始结构参考NzTreeNodeOptions | array | \[] | +| `[ngModel]` | 元数据 `Deprecated` | NzTreeNode[] | \[] | +| `[nzDefaultExpandAll]` | 默认展开所有节点 `Deprecated` | boolean | false | +| `[nzDefaultExpandedKeys]` | 展开指定的节点 `Deprecated` | string\[] | \[] | +| `[nzDefaultCheckedKeys]` | 指定选中复选框的节点 `Deprecated` | string\[] | \[] | +| `[nzDefaultSelectedKeys]` | 指定选中的节点 `Deprecated` | string\[] | \[] | +| `[nzData]` | 元数据 | NzTreeNodeOptions[] / NzTreeNode[] | \[] | | `[nzCheckable]` | 节点前添加 Checkbox 复选框 | boolean | false | | `[nzShowExpand]` | 节点前添加展开图标 | boolean | true | | `[nzShowLine]` | 是否展示连接线 | boolean | false | @@ -23,10 +28,10 @@ subtitle: 树形控件 | `[nzDraggable]` | 设置节点可拖拽(IE>8) | boolean | false | | `[nzMultiple]` | 支持点选多个节点(节点本身) | boolean | false | | `[nzCheckStrictly]` | checkable状态下节点选择完全受控(父子节点选中状态不再关联) | boolean | false | -| `[nzDefaultExpandAll]` | 默认展开所有树节点 | boolean | false | -| `[nzDefaultExpandedKeys]` | 默认展开指定的树节点 | string\[] | \[] | -| `[nzDefaultCheckedKeys]` | 默认选中复选框的树节点 | string\[] | \[] | -| `[nzDefaultSelectedKeys]` | 默认选中的树节点(nzMultiple为true) | string\[] | \[] | +| `[nzExpandAll]` | 默认展开所有树节点 | boolean | false | +| `[nzExpandedKeys]` | 展开指定的树节点 | string\[] | \[] | +| `[nzCheckedKeys]` | 指定选中复选框的树节点 | string\[] | \[] | +| `[nzSelectedKeys]` | 指定选中的树节点(nzMultiple为true) | string\[] | \[] | | `[nzSearchValue]` | 按需筛选树高亮节点(结合搜索控件) | string | null | | `[nzBeforeDrop]` | drop前二次校验,允许用户自行决定是否允许放置 | `(confirm: NzFormatBeforeDropEvent) => Observable` | - | | `(nzClick)` | 点击树节点触发 | EventEmitter | - | @@ -34,7 +39,8 @@ subtitle: 树形控件 | `(nzContextMenu)` | 右键树节点触发 | EventEmitter | - | | `(nzCheckBoxChange)` | 点击树节点 Checkbox 触发 | EventEmitter | - | | `(nzExpandChange)` | 点击展开树节点图标触发 |EventEmitter | - | -| `(nzOnSearchNode)` | 搜索节点时调用(与nzSearchValue配合使用) | EventEmitter | - | +| `(nzSearchValueChange)` | 搜索节点时调用(与nzSearchValue配合使用) | EventEmitter | - | +| `(nzOnSearchNode)` | 搜索节点时调用(与nzSearchValue配合使用) `Deprecated` | EventEmitter | - | | `(nzOnDragStart)` | 开始拖拽时调用 | EventEmitter | - | | `(nzOnDragEnter)` | dragenter 触发时调用 | EventEmitter | - | | `(nzOnDragOver)` | dragover 触发时调用 | EventEmitter | - | @@ -50,6 +56,8 @@ subtitle: 树形控件 | getCheckedNodeList | 获取组件 checkBox 被点击选中的节点 | NzTreeNode[] | [] | | getSelectedNodeList | 获取组件被选中的节点 | NzTreeNode[] | [] | | getHalfCheckedNodeList | 获取组件半选状态节点 | NzTreeNode[] | [] | +| getExpandedNodeList | 获取组件展开状态节点 | NzTreeNode[] | [] | +| getMatchedNodeList | 获取组搜索匹配到的节点 | NzTreeNode[] | [] | #### NzTreeNodeOptions props @@ -65,7 +73,7 @@ subtitle: 树形控件 | selectable | 设置节点是否可被选中 | boolean | true | | disabled | 设置是否禁用节点(不可进行任何操作) | boolean | false | | disableCheckbox | 设置节点禁用 Checkbox | boolean | false | -| [key: string] | 自定义数据 | any | - | +| [key: string] | 自定义数据,可通过 NzTreeNode 的 origin 字段获取 | any | - | #### NzFormatEmitEvent props @@ -75,9 +83,12 @@ subtitle: 树形控件 | node | 当前操作节点(拖拽时表示目标节点) | NzTreeNode | null | | event | 原生事件 | enum: `MouseEvent` `DragEvent` | null | | dragNode? | 当前拖拽节点(拖拽时存在) | NzTreeNode | null | -| selectedKeys? | 已选中的节点(单击时存在) | array | [] | -| checkedKeys? | checkBox 已选中的节点(点击 checkBox 存在) | array | [] | -| matchededKeys? | 搜索时匹配到的节点 | array | [] | +| selectedKeys? | 已选中的节点key(单击时存在) | NzTreeNode[] | [] | +| checkedKeys? | checkBox 已选中的节点key(点击 checkBox 存在) | NzTreeNode[] | [] | +| matchedKeys? | 搜索时匹配到的节点key | NzTreeNode[] | [] | +| keys? | 非拖拽事件相关的全部节点的key数组 | string[] | [] | +| nodes? | 非拖拽事件相关的全部节点 | NzTreeNode[] | [] | + #### NzFormatBeforeDropEvent props @@ -94,7 +105,7 @@ subtitle: 树形控件 | title | 标题 | string | NzTreeNodeOptions.title | | key | key值 | string | NzTreeNodeOptions.key | | level | 层级(最顶层为0,子节点逐层加1) | number | number | -| children | 子节点 | array | array | +| children | 子节点 | array | NzTreeNode[] | | origin | 原始节点树结构(用户提供,用于展示额外信息) | NzTreeNodeOptions | - | | getParentNode | 获取父节点 | function | `NzTreeNode` 或 `null` | | isLeaf | 是否为叶子节点 | boolean | `true` 或 `false` | @@ -109,8 +120,11 @@ subtitle: 树形控件 | isLoading | 是否异步加载状态(影响展开图标展示) | boolean | `true` 或 `false` | | isMatched | title是否包含nzSearchValue(搜索使用) | boolean | `true` 或 `false` | | getChildren | 获取子节点,返回NzTreeNode数组 | function | NzTreeNode[] | -| addChildren | 添加子节点,接收NzTreeNode或NzTreeNodeOptions数组,第二个参数为插入的索引位置 | (children: array, index?: number )=>{} | void | -| clearChildren | 清除子节点 | function | void | +| addChildren | 添加子节点,接收NzTreeNode或NzTreeNodeOptions数组,第二个参数为插入的索引位置,默认插入末尾 | (children: array, index?: number )=>{} | void | +| setChecked | 设置checked状态,参数为checked和halfChecked | (checked: boolean, halfChecked: boolean=false)=>{} | void | +| setExpanded | 设置expanded状态 | (value: boolean)=>{} | void | +| setSelected | 设置selected状态 | (value: boolean)=>{} | void | + ## 注意 `NzTreeNodeOptions` 可以接受用户自定义属性,可通过 `NzTreeNode` 的 `origin` 属性取得。 \ No newline at end of file diff --git a/components/tree/interface.ts b/components/tree/interface.ts index 15ec82a6e09..b127e73d6c9 100644 --- a/components/tree/interface.ts +++ b/components/tree/interface.ts @@ -8,6 +8,8 @@ export interface NzFormatEmitEvent { selectedKeys?: NzTreeNode[]; checkedKeys?: NzTreeNode[]; matchedKeys?: NzTreeNode[]; + nodes?: NzTreeNode[]; + keys?: string[]; } export interface NzFormatBeforeDropEvent { diff --git a/components/tree/nz-tree-node.component.html b/components/tree/nz-tree-node.component.html index 3642f1b8d67..ba9abdb0786 100644 --- a/components/tree/nz-tree-node.component.html +++ b/components/tree/nz-tree-node.component.html @@ -1,53 +1,62 @@ -
  • +
  • + [ngClass]="nzNodeSwitcherClass" + [class.ant-tree-switcher_open]="isSwitcherOpen" + [class.ant-tree-switcher_close]="isSwitcherClose" + (click)="_clickExpand($event)"> - + - + [class.ant-tree-checkbox-disabled]="(nzTreeNode.isDisabled || nzTreeNode.isDisableCheckbox)" + (click)="_clickCheckBox($event)"> + - - - - {{matchValue[0]}}{{nzSearchValue}}{{matchValue[1]}} - - - - {{nzTreeNode.title}} - + [class.draggable]="canDraggable"> + + + + + + + + {{highlightKeys[0]}}{{nzSearchValue}}{{highlightKeys[1]}} + + + + {{nzTreeNode.title}} + + -
      - + active', animate('150ms ease-in')), - transition('active => inactive', animate('150ms ease-out')) + transition('inactive => active', animate('100ms ease-in')), + transition('active => inactive', animate('100ms ease-out')) ]) ] }) -export class NzTreeNodeComponent implements OnInit, AfterViewInit { - dragPos = 2; - prefixCls = 'ant-tree'; - _treeNode; - _expandAll = false; - _defaultCheckedKeys = []; - _defaultExpandedKeys = []; - _defaultSelectedKeys = []; - _searchValue = ''; - matchValue = []; - // 拖动划过状态 - dragPosClass: object = { - '0' : 'drag-over', - '1' : 'drag-over-gap-bottom', - '-1': 'drag-over-gap-top' - }; - +export class NzTreeNodeComponent implements OnInit, OnChanges { @ViewChild('dragElement') dragElement: ElementRef; - @Input() nzShowLine: boolean; - @Input() nzShowExpand: boolean; - @Input() nzDraggable: boolean; - @Input() nzMultiple: boolean; - @Input() nzCheckable: boolean; - @Input() nzAsyncData; - @Input() nzCheckStrictly: boolean; + @Input() @InputBoolean() nzShowLine: boolean; + @Input() @InputBoolean() nzShowExpand: boolean; + @Input() @InputBoolean() nzDraggable: boolean; + @Input() @InputBoolean() nzMultiple: boolean; + @Input() @InputBoolean() nzCheckable: boolean; + @Input() @InputBoolean() nzAsyncData: boolean; + @Input() @InputBoolean() nzCheckStrictly: boolean; @Input() nzTreeTemplate: TemplateRef; @Input() nzBeforeDrop: (confirm: NzFormatBeforeDropEvent) => Observable; @Input() - set nzTreeNode(node: NzTreeNode) { - this._treeNode = node; + set nzTreeNode(value: NzTreeNode) { + // add to checked list & selected list + if (value.isChecked) { + this.nzTreeService.setCheckedNodeList(value); + } + // add select list + if (value.isSelected) { + this.nzTreeService.setSelectedNodeList(value, this.nzMultiple); + } + if (!value.isLeaf) { + this.nzTreeService.setExpandedNodeList(value); + } + this._nzTreeNode = value; } get nzTreeNode(): NzTreeNode { - return this._treeNode; + return this._nzTreeNode; } + // TODO: Deprecated @Input() set nzDefaultExpandAll(value: boolean) { - if (value && this.nzTreeNode) { - this.nzTreeNode.isExpanded = value; + this._nzExpandAll = value; + if (value && this.nzTreeNode && !this.nzTreeNode.isLeaf) { + this.nzTreeNode.setExpanded(true); + this.nzTreeService.setExpandedNodeList(this.nzTreeNode); } - this._expandAll = value; } get nzDefaultExpandAll(): boolean { - return this._expandAll; - } - - @Input() - set nzDefaultCheckedKeys(value: string[]) { - // should set checked node list - this._defaultCheckedKeys = value; - if (value && value.indexOf(this.nzTreeNode.key) > -1) { - if (this.nzCheckStrictly) { - this.nzTreeService.setCheckedNodeListStrict(this.nzTreeNode); - } else { - this.nzTreeService.setCheckedNodeList(this.nzTreeNode); - } - } - } - - get nzDefaultCheckedKeys(): string[] { - return this._defaultCheckedKeys; - } - - @Input() - set nzDefaultExpandedKeys(value: string[]) { - this._defaultExpandedKeys = value; - if (value && value.indexOf(this.nzTreeNode.key) > -1) { - this.nzTreeNode.isExpanded = true; - } - } - - get nzDefaultExpandedKeys(): string[] { - return this._defaultExpandedKeys; + return this._nzExpandAll; } + // default set @Input() - set nzDefaultSelectedKeys(value: string[]) { - this._defaultSelectedKeys = value; - if (value && !this.nzTreeNode.isDisabled && value.indexOf(this.nzTreeNode.key) > -1) { - this.nzTreeNode.isSelected = true; - this.nzTreeService.setSelectedNodeList(this.nzTreeNode, this.nzMultiple); + set nzExpandAll(value: boolean) { + this._nzExpandAll = value; + if (value && this.nzTreeNode && !this.nzTreeNode.isLeaf) { + this.nzTreeNode.setExpanded(true); + this.nzTreeService.setExpandedNodeList(this.nzTreeNode); } } - get nzDefaultSelectedKeys(): string[] { - return this._defaultSelectedKeys; + get nzExpandAll(): boolean { + return this._nzExpandAll; } @Input() set nzSearchValue(value: string) { + this.highlightKeys = []; if (value && this.nzTreeNode.title.includes(value)) { this.nzTreeNode.isMatched = true; - this.matchValue = []; // match the search value const index = this.nzTreeNode.title.indexOf(value); - this.matchValue.push(this.nzTreeNode.title.slice(0, index)); - this.matchValue.push(this.nzTreeNode.title.slice(index + value.length, this.nzTreeNode.title.length)); + this.highlightKeys.push(this.nzTreeNode.title.slice(0, index)); + this.highlightKeys.push(this.nzTreeNode.title.slice(index + value.length, this.nzTreeNode.title.length)); } else { // close the node if title does't contain search value this.nzTreeNode.isMatched = false; - this.matchValue = []; } this._searchValue = value; } @@ -151,14 +116,7 @@ export class NzTreeNodeComponent implements OnInit, AfterViewInit { return this._searchValue; } - get loadingStyle(): { [ key: string ]: string } { - const isLoading = this.nzTreeNode.isLoading && !this.nzTreeNode.isLeaf; - return { - position : isLoading ? 'relative' : '', - transform: isLoading ? 'translateX(0%)' : '' - }; - } - + // Output @Output() clickNode: EventEmitter = new EventEmitter(); @Output() dblClick: EventEmitter = new EventEmitter(); @Output() contextMenu: EventEmitter = new EventEmitter(); @@ -171,38 +129,172 @@ export class NzTreeNodeComponent implements OnInit, AfterViewInit { @Output() nzDrop: EventEmitter = new EventEmitter(); @Output() nzDragEnd: EventEmitter = new EventEmitter(); - constructor(private nzTreeService: NzTreeService, private ngZone: NgZone, private renderer: Renderer2) { + // default var + prefixCls = 'ant-tree'; + highlightKeys = []; + nzNodeClass = {}; + nzNodeSwitcherClass = {}; + nzNodeContentClass = {}; + nzNodeContentIconClass = {}; + nzNodeContentLoadingClass = {}; + nzNodeChildrenClass = {}; + + /** + * drag var + */ + dragPos = 2; + dragPosClass: object = { + '0' : 'drag-over', + '1' : 'drag-over-gap-bottom', + '-1': 'drag-over-gap-top' + }; + + /** + * default set + */ + _nzTreeNode: NzTreeNode; + _searchValue = ''; + _nzExpandAll = false; + + get canDraggable(): boolean | null { + return (this.nzDraggable && this.nzTreeNode && !this.nzTreeNode.isDisabled) ? true : null; } - ngOnInit(): void { - if (this.nzTreeNode.isChecked) { - // associate nodes - if (this.nzCheckStrictly) { - this.nzTreeService.setCheckedNodeListStrict(this.nzTreeNode); - } else { - this.nzTreeService.setCheckedNodeList(this.nzTreeNode); + get isSwitcherOpen(): boolean { + return (this.nzTreeNode.isExpanded && !this.nzTreeNode.isLeaf); + } + + get isSwitcherClose(): boolean { + return (!this.nzTreeNode.isExpanded && !this.nzTreeNode.isLeaf); + } + + /** + * reset node class + */ + setClassMap(): void { + this.nzNodeClass = { + [ `${this.prefixCls}-treenode-disabled` ]: this.nzTreeNode.isDisabled + }; + this.nzNodeSwitcherClass = { + [ `${this.prefixCls}-switcher` ] : true, + [ `${this.prefixCls}-switcher-noop` ]: this.nzTreeNode.isLeaf + }; + this.nzNodeContentClass = { + [ `${this.prefixCls}-node-content-wrapper` ]: true + }; + this.nzNodeContentIconClass = { + [ `${this.prefixCls}-iconEle` ] : true, + [ `${this.prefixCls}-icon__customize` ]: true + }; + this.nzNodeContentLoadingClass = { + [ `${this.prefixCls}-iconEle` ]: true + }; + this.nzNodeChildrenClass = { + [ `${this.prefixCls}-child-tree` ] : true, + [ `${this.prefixCls}-child-tree-open` ]: true + }; + } + + /** + * click node to select, 200ms to dbl click + */ + @HostListener('click', [ '$event' ]) + nzClick(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + if (this.nzTreeNode.isSelectable) { + this.nzTreeService.setNodeActive(this.nzTreeNode, this.nzMultiple); + } + this.clickNode.emit(this.nzTreeService.formatEvent('click', this.nzTreeNode, event)); + } + + @HostListener('dblclick', [ '$event' ]) + nzDblClick(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + this.dblClick.emit(this.nzTreeService.formatEvent('dblclick', this.nzTreeNode, event)); + } + + /** + * @param event + */ + @HostListener('contextmenu', [ '$event' ]) + nzContextMenu(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + this.contextMenu.emit(this.nzTreeService.formatEvent('contextmenu', this.nzTreeNode, event)); + } + + /** + * collapse node + * @param event + */ + _clickExpand(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + if (!this.nzTreeNode.isLoading && !this.nzTreeNode.isLeaf) { + // set async state + if (this.nzAsyncData && this.nzTreeNode.getChildren().length === 0 && !this.nzTreeNode.isExpanded) { + this.nzTreeNode.isLoading = true; } + this.nzTreeNode.setExpanded(!this.nzTreeNode.isExpanded); + this.nzTreeService.setExpandedNodeList(this.nzTreeNode); + this.clickExpand.emit(this.nzTreeService.formatEvent('expand', this.nzTreeNode, event)); } - // add select list - if (this.nzTreeNode.isSelected) { - this.nzTreeService.setSelectedNodeList(this.nzTreeNode, this.nzMultiple); + } + + /** + * check node + * @param event + */ + _clickCheckBox(event: MouseEvent): void { + event.preventDefault(); + event.stopPropagation(); + // return if node is disabled + if (isCheckDisabled(this.nzTreeNode)) { + return; + } + this.nzTreeNode.setChecked(!this.nzTreeNode.isChecked); + this.nzTreeService.setCheckedNodeList(this.nzTreeNode); + if (!this.nzCheckStrictly) { + this.nzTreeService.conduct(this.nzTreeNode); } + this.clickCheckBox.emit(this.nzTreeService.formatEvent('check', this.nzTreeNode, event)); + } + + /** + * drag event + * @param e + */ + clearDragClass(): void { + const dragClass = [ 'drag-over-gap-top', 'drag-over-gap-bottom', 'drag-over' ]; + dragClass.forEach(e => { + this.renderer.removeClass(this.dragElement.nativeElement, e); + }); } handleDragStart(e: DragEvent): void { e.stopPropagation(); + try { + // ie throw error + // firefox-need-it + e.dataTransfer.setData('text/plain', ''); + } catch (error) { + // empty + } this.nzTreeService.setSelectedNode(this.nzTreeNode); - this.nzTreeNode.isExpanded = false; + this.nzTreeNode.setExpanded(false); this.nzDragStart.emit(this.nzTreeService.formatEvent('dragstart', null, e)); } handleDragEnter(e: DragEvent): void { e.preventDefault(); e.stopPropagation(); + // reset position + this.dragPos = 2; this.ngZone.run(() => { - this.nzTreeService.targetNode = this.nzTreeNode; if ((this.nzTreeNode !== this.nzTreeService.getSelectedNode()) && !this.nzTreeNode.isLeaf) { - this.nzTreeNode.isExpanded = true; + this.nzTreeNode.setExpanded(true); } }); this.nzDragEnter.emit(this.nzTreeService.formatEvent('dragenter', this.nzTreeNode, e)); @@ -211,11 +303,12 @@ export class NzTreeNodeComponent implements OnInit, AfterViewInit { handleDragOver(e: DragEvent): void { e.preventDefault(); e.stopPropagation(); - if (this.dragPos !== this.nzTreeService.calcDropPosition(e)) { - this._clearDragClass(); - this.dragPos = this.nzTreeService.calcDropPosition(e); + const dropPosition = this.nzTreeService.calcDropPosition(e); + if (this.dragPos !== dropPosition) { + this.clearDragClass(); + this.dragPos = dropPosition; + // leaf node will pass if (!(this.dragPos === 0 && this.nzTreeNode.isLeaf)) { - // leaf node can not be inserted this.renderer.addClass(this.dragElement.nativeElement, this.dragPosClass[ this.dragPos ]); } } @@ -225,7 +318,7 @@ export class NzTreeNodeComponent implements OnInit, AfterViewInit { handleDragLeave(e: DragEvent): void { e.stopPropagation(); this.ngZone.run(() => { - this._clearDragClass(); + this.clearDragClass(); }); this.nzDragLeave.emit(this.nzTreeService.formatEvent('dragleave', this.nzTreeNode, e)); } @@ -233,28 +326,32 @@ export class NzTreeNodeComponent implements OnInit, AfterViewInit { handleDragDrop(e: DragEvent): void { e.preventDefault(); e.stopPropagation(); - this.dragPos = this.nzTreeService.calcDropPosition(e); this.ngZone.run(() => { + this.clearDragClass(); + if (this.nzTreeService.getSelectedNode() === this.nzTreeNode) { + console.log('Can not be dropped to self node(include dragNode\'s children node)'); + return; + } else if (this.dragPos === 0 && this.nzTreeNode.isLeaf) { + console.log('Can not drop to leaf node'); + return; + } // pass if node is leafNo - if (this.nzTreeNode !== this.nzTreeService.getSelectedNode() && !(this.dragPos === 0 && this.nzTreeNode.isLeaf)) { - if (this.nzBeforeDrop) { - this.nzBeforeDrop({ - dragNode: this.nzTreeService.getSelectedNode(), - node : this.nzTreeNode, - pos : this.dragPos - }).subscribe((canDrop: boolean) => { - if (canDrop) { - this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos); - } - this.nzDrop.emit(this.nzTreeService.formatEvent('drop', this.nzTreeNode, e)); - this.nzDragEnd.emit(this.nzTreeService.formatEvent('dragend', this.nzTreeNode, e)); - }); - } else { - this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos); + if (this.nzBeforeDrop) { + this.nzBeforeDrop({ + dragNode: this.nzTreeService.getSelectedNode(), + node : this.nzTreeNode, + pos : this.dragPos + }).subscribe((canDrop: boolean) => { + if (canDrop) { + this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos); + } this.nzDrop.emit(this.nzTreeService.formatEvent('drop', this.nzTreeNode, e)); - } + this.nzDragEnd.emit(this.nzTreeService.formatEvent('dragend', this.nzTreeNode, e)); + }); + } else if (this.nzTreeNode) { + this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos); + this.nzDrop.emit(this.nzTreeService.formatEvent('drop', this.nzTreeNode, e)); } - this._clearDragClass(); }); } @@ -269,80 +366,22 @@ export class NzTreeNodeComponent implements OnInit, AfterViewInit { }); } - ngAfterViewInit(): void { - if (this.nzDraggable) { - this.ngZone.runOutsideAngular(() => { - fromEvent(this.dragElement.nativeElement, 'dragstart').subscribe((e: DragEvent) => this.handleDragStart(e)); - fromEvent(this.dragElement.nativeElement, 'dragenter').subscribe((e: DragEvent) => this.handleDragEnter(e)); - fromEvent(this.dragElement.nativeElement, 'dragover').subscribe((e: DragEvent) => this.handleDragOver(e)); - fromEvent(this.dragElement.nativeElement, 'dragleave').subscribe((e: DragEvent) => this.handleDragLeave(e)); - fromEvent(this.dragElement.nativeElement, 'drop').subscribe((e: DragEvent) => this.handleDragDrop(e)); - fromEvent(this.dragElement.nativeElement, 'dragend').subscribe((e: DragEvent) => this.handleDragEnd(e)); - }); - } - } - - _clearDragClass(): void { - const dragClass = [ 'drag-over-gap-top', 'drag-over-gap-bottom', 'drag-over' ]; - dragClass.forEach(e => { - this.renderer.removeClass(this.dragElement.nativeElement, e); + constructor(private nzTreeService: NzTreeService, private ngZone: NgZone, private renderer: Renderer2, private elRef: ElementRef) { + ngZone.runOutsideAngular(() => { + fromEvent(this.elRef.nativeElement, 'dragstart').subscribe((e: DragEvent) => this.handleDragStart(e)); + fromEvent(this.elRef.nativeElement, 'dragenter').subscribe((e: DragEvent) => this.handleDragEnter(e)); + fromEvent(this.elRef.nativeElement, 'dragover').subscribe((e: DragEvent) => this.handleDragOver(e)); + fromEvent(this.elRef.nativeElement, 'dragleave').subscribe((e: DragEvent) => this.handleDragLeave(e)); + fromEvent(this.elRef.nativeElement, 'drop').subscribe((e: DragEvent) => this.handleDragDrop(e)); + fromEvent(this.elRef.nativeElement, 'dragend').subscribe((e: DragEvent) => this.handleDragEnd(e)); }); } - _clickNode($event: MouseEvent, node: NzTreeNode): void { - $event.preventDefault(); - $event.stopPropagation(); - if (this.nzTreeNode.isSelectable && !this.nzTreeNode.isDisabled) { - this.nzTreeService.initNodeActive(this.nzTreeNode, this.nzMultiple); - } - this.clickNode.emit(this.nzTreeService.formatEvent('click', node, $event)); - } - - _dblClickNode($event: MouseEvent, node: NzTreeNode): void { - $event.preventDefault(); - $event.stopPropagation(); - this.dblClick.emit(this.nzTreeService.formatEvent('dblclick', node, $event)); - } - - _contextMenuNode($event: MouseEvent, node: NzTreeNode): void { - $event.preventDefault(); - $event.stopPropagation(); - this.contextMenu.emit(this.nzTreeService.formatEvent('contextmenu', node, $event)); - } - - _clickCheckBox($event: MouseEvent, node: NzTreeNode): void { - $event.preventDefault(); - $event.stopPropagation(); - // return if node is disabled - if (node.isDisableCheckbox || node.isDisabled) { - return; - } - node.isChecked = !node.isChecked; - if (this.nzCheckStrictly) { - node.isAllChecked = node.isChecked; - node.isHalfChecked = false; - this.nzTreeService.setCheckedNodeListStrict(this.nzTreeNode); - } else { - this.nzTreeService.checkTreeNode(node); - this.nzTreeService.setCheckedNodeList(this.nzTreeNode); - } - this.clickCheckBox.emit(this.nzTreeService.formatEvent('check', node, $event)); + ngOnInit(): void { + this.setClassMap(); } - _clickExpand($event: MouseEvent, node: NzTreeNode): void { - $event.preventDefault(); - $event.stopPropagation(); - if (!this.nzTreeNode.isLoading) { - if (!node.isLeaf) { - // set async state - if (this.nzAsyncData && this.nzTreeNode.getChildren().length === 0 && !this.nzTreeNode.isExpanded) { - this.nzTreeNode.isLoading = true; - } - node.isExpanded = !this.nzTreeNode.isExpanded; - } - if (!this.nzTreeNode.isLeaf) { - this.clickExpand.emit(this.nzTreeService.formatEvent('expand', node, $event)); - } - } + ngOnChanges(changes: SimpleChanges): void { + this.setClassMap(); } } diff --git a/components/tree/nz-tree-node.ts b/components/tree/nz-tree-node.ts index 9b569cc2235..3d3a1633a1d 100644 --- a/components/tree/nz-tree-node.ts +++ b/components/tree/nz-tree-node.ts @@ -1,6 +1,7 @@ export interface NzTreeNodeOptions { title: string; key: string; + icon?: string; isLeaf?: boolean; checked?: boolean; selected?: boolean; @@ -9,8 +10,9 @@ export interface NzTreeNodeOptions { disableCheckbox?: boolean; expanded?: boolean; children?: NzTreeNodeOptions[]; + // tslint:disable-next-line:no-any - [key: string]: any; + [ key: string ]: any; } export class NzTreeNode { @@ -35,29 +37,26 @@ export class NzTreeNode { isMatched: boolean; constructor(option: NzTreeNodeOptions, parent: NzTreeNode = null) { - this.title = option.title || '---'; + this.title = option.title || 'undefined'; this.key = option.key || null; this.isLeaf = option.isLeaf || false; this.origin = option; - this.children = []; this.parentNode = parent; - // option params this.isChecked = option.checked || false; this.isSelectable = option.disabled || (option.selectable === false ? false : true); this.isDisabled = option.disabled || false; this.isDisableCheckbox = option.disableCheckbox || false; - this.isExpanded = option.expanded || false; - + this.isExpanded = option.isLeaf ? false : (option.expanded || false); this.isAllChecked = option.checked || false; this.isHalfChecked = false; - this.isSelected = option.selected || false; + this.isSelected = (!option.disabled && option.selected) || false; this.isLoading = false; this.isMatched = false; /** - * 初始化时父节点checked状态影响全部子节点 + * parent's checked status will affect children while initializing */ if (parent) { this.level = parent.level + 1; @@ -76,6 +75,23 @@ export class NzTreeNode { } } + public setChecked(checked: boolean = false, halfChecked: boolean = false): void { + this.origin.checked = checked; + this.isChecked = checked; + this.isAllChecked = checked; + this.isHalfChecked = halfChecked; + } + + public setExpanded(value: boolean): void { + this.origin.expanded = value; + this.isExpanded = value; + } + + public setSelected(value: boolean): void { + this.origin.selected = value; + this.isSelected = value; + } + public getParentNode(): NzTreeNode { return this.parentNode; } @@ -89,35 +105,30 @@ export class NzTreeNode { */ // tslint:disable-next-line:no-any public addChildren(children: any[], childPos: number = -1): void { - if (this.isLeaf) { - // remove loading state - this.isLoading = false; - } else { + if (!this.isLeaf) { children.forEach( (node) => { - let tNode = node; - if (tNode instanceof NzTreeNode) { - tNode = new NzTreeNode({ - checked: !tNode.origin.disabled && !tNode.origin.disableCheckbox && this.isChecked, - ...(tNode.origin as NzTreeNodeOptions) - }, this); + const refreshLevel = (n: NzTreeNode) => { + n.getChildren().forEach(c => { + c.level = c.getParentNode().level + 1; + refreshLevel(c); + }); + }; + let child = node; + if (child instanceof NzTreeNode) { + child.parentNode = this; } else { - node.checked = !node.disabled && !node.disableCheckbox && this.isChecked; - tNode = new NzTreeNode(node, this); + child = new NzTreeNode(node, this); } - tNode.level = this.level + 1; + child.level = this.level + 1; + refreshLevel(child); try { - childPos === -1 ? this.children.push(tNode) : this.children.splice(childPos, 0, tNode); + childPos === -1 ? this.children.push(child) : this.children.splice(childPos, 0, child); } catch (e) { - } }); // remove loading state this.isLoading = false; } } - - public clearChildren(): void { - this.children = []; - } } diff --git a/components/tree/nz-tree-util.ts b/components/tree/nz-tree-util.ts new file mode 100644 index 00000000000..07215940f6f --- /dev/null +++ b/components/tree/nz-tree-util.ts @@ -0,0 +1,11 @@ +import { NzTreeNode } from './nz-tree-node'; + +export function isCheckDisabled(node: NzTreeNode): boolean { + const { isDisabled, isDisableCheckbox } = node; + return !!(isDisabled || isDisableCheckbox); +} + +// tslint:disable-next-line:no-any +export function isInArray(needle: any, haystack: any[]): boolean { + return (haystack.length > 0 && haystack.indexOf(needle) > -1); +} diff --git a/components/tree/nz-tree.component.html b/components/tree/nz-tree.component.html index 95f2d3a429a..b16cf9e4ac7 100644 --- a/components/tree/nz-tree.component.html +++ b/components/tree/nz-tree.component.html @@ -1,32 +1,32 @@
        - + + (nzDragEnd)="nzOnDragEnd.emit($event)"> +
      \ No newline at end of file diff --git a/components/tree/nz-tree.component.ts b/components/tree/nz-tree.component.ts index 26d9d64ceb9..89e98b9d221 100644 --- a/components/tree/nz-tree.component.ts +++ b/components/tree/nz-tree.component.ts @@ -1,8 +1,17 @@ -import { forwardRef, Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core'; +import { + forwardRef, + Component, + ContentChild, + EventEmitter, + Input, + OnDestroy, + OnInit, Output, TemplateRef +} from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Observable } from 'rxjs'; - -import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from './interface'; +import { Observable, Subject, Subscription } from 'rxjs'; +import { isNotNil } from '../core/util/check'; +import { InputBoolean } from '../core/util/convert'; +import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from '../tree/interface'; import { NzTreeNode } from './nz-tree-node'; import { NzTreeService } from './nz-tree.service'; @@ -18,60 +27,112 @@ import { NzTreeService } from './nz-tree.service'; } ] }) -export class NzTreeComponent implements OnInit { - _searchValue; - _showLine = false; - _prefixCls = 'ant-tree'; - classMap = { - [ this._prefixCls ] : true, - [ this._prefixCls + '-show-line' ]: false, - [ 'draggable-tree' ] : false - }; - ngModelNodes: NzTreeNode[] = []; - defaultCheckedKeys: string[] = []; - @ContentChild('nzTreeTemplate') nzTreeTemplate: TemplateRef<{}>; - - @Input() nzCheckStrictly: boolean = false; - @Input() nzCheckable; - @Input() nzShowExpand: boolean = true; - @Input() nzAsyncData: boolean = false; - @Input() nzDraggable; - @Input() nzMultiple; - @Input() nzDefaultExpandAll: boolean = false; - @Input() nzDefaultExpandedKeys: string[] = []; - @Input() nzDefaultSelectedKeys: string[] = []; + +export class NzTreeComponent implements OnInit, OnDestroy { + @Input() @InputBoolean() nzShowIcon = false; + @Input() @InputBoolean() nzShowLine = false; + @Input() @InputBoolean() nzCheckStrictly = false; + @Input() @InputBoolean() nzCheckable = false; + @Input() @InputBoolean() nzShowExpand = true; + @Input() @InputBoolean() nzAsyncData = false; + @Input() @InputBoolean() nzDraggable = false; + @Input() @InputBoolean() nzMultiple = false; + @Input() @InputBoolean() nzExpandAll: boolean = false; + // TODO: Deprecated + @Input() @InputBoolean() nzDefaultExpandAll: boolean = false; @Input() nzBeforeDrop: (confirm: NzFormatBeforeDropEvent) => Observable; + + @Input() + // tslint:disable-next-line:no-any + set nzData(value: any[]) { + if (Array.isArray(value) && value.length > 0) { + if (!this.nzTreeService.isArrayOfNzTreeNode(value)) { + // has not been new NzTreeNode + this.nzNodes = value.map(item => (new NzTreeNode(item))); + } else { + this.nzNodes = value; + } + this.nzTreeService.conductOption.isCheckStrictly = this.nzCheckStrictly; + this.nzTreeService.initTree(this.nzNodes); + } else { + if (value !== null) { + console.log('nzData only accepts an array and should be not empty'); + } + } + } + + /** + * TODO: Deprecated + */ + @Input() + set nzDefaultExpandedKeys(value: string[]) { + setTimeout(() => { + this.nzDefaultSubject.next({ type: 'nzExpandedKeys', keys: value }); + }); + } + + @Input() + set nzDefaultSelectedKeys(value: string[]) { + setTimeout(() => { + this.nzDefaultSubject.next({ type: 'nzSelectedKeys', keys: value }); + }); + } + @Input() set nzDefaultCheckedKeys(value: string[]) { - this.defaultCheckedKeys = value; - this.nzTreeService.initTreeNodes(this.ngModelNodes, this.nzDefaultCheckedKeys, this.nzCheckStrictly); + setTimeout(() => { + this.nzDefaultSubject.next({ type: 'nzCheckedKeys', keys: value }); + }); } - get nzDefaultCheckedKeys(): string[] { - return this.defaultCheckedKeys; + + /** + * END Deprecated + */ + + @Input() + set nzExpandedKeys(value: string[]) { + setTimeout(() => { + this.nzDefaultSubject.next({ type: 'nzExpandedKeys', keys: value }); + }); } @Input() - set nzShowLine(value: boolean) { - this._showLine = value; - this.setClassMap(); + set nzSelectedKeys(value: string[]) { + setTimeout(() => { + this.nzDefaultSubject.next({ type: 'nzSelectedKeys', keys: value }); + }); } - get nzShowLine(): boolean { - return this._showLine; + @Input() + set nzCheckedKeys(value: string[]) { + setTimeout(() => { + this.nzDefaultSubject.next({ type: 'nzCheckedKeys', keys: value }); + }); } @Input() set nzSearchValue(value: string) { this._searchValue = value; this.nzTreeService.searchExpand(value); - this.nzOnSearchNode.emit(this.nzTreeService.formatEvent('search', null, null)); + if (isNotNil(value)) { + this.nzSearchValueChange.emit(this.nzTreeService.formatEvent('search', null, null)); + this.nzOnSearchNode.emit(this.nzTreeService.formatEvent('search', null, null)); + } } get nzSearchValue(): string { return this._searchValue; } + // model bind + @Output() nzExpandedKeysChange: EventEmitter = new EventEmitter(); + @Output() nzSelectedKeysChange: EventEmitter = new EventEmitter(); + @Output() nzCheckedKeysChange: EventEmitter = new EventEmitter(); + + @Output() nzSearchValueChange: EventEmitter = new EventEmitter(); + // TODO: Deprecated @Output() nzOnSearchNode: EventEmitter = new EventEmitter(); + @Output() nzClick: EventEmitter = new EventEmitter(); @Output() nzDblClick: EventEmitter = new EventEmitter(); @Output() nzContextMenu: EventEmitter = new EventEmitter(); @@ -85,17 +146,20 @@ export class NzTreeComponent implements OnInit { @Output() nzOnDrop: EventEmitter = new EventEmitter(); @Output() nzOnDragEnd: EventEmitter = new EventEmitter(); + // tslint:disable-next-line:no-any + @ContentChild('nzTreeTemplate') nzTreeTemplate: TemplateRef; + _searchValue = ''; + // tslint:disable-next-line:no-any + nzDefaultSubject = new Subject(); + nzDefaultSubscription: Subscription; + nzNodes: NzTreeNode[] = []; + prefixCls = 'ant-tree'; + nzTreeClass = {}; + + // TODO: Deprecated onChange: (value: NzTreeNode[]) => void = () => null; onTouched: () => void = () => null; - setClassMap(): void { - this.classMap = { - [ this._prefixCls ] : true, - [ this._prefixCls + '-show-line' ]: this.nzShowLine, - [ 'draggable-tree' ] : this.nzDraggable - }; - } - /** * public function */ @@ -111,19 +175,42 @@ export class NzTreeComponent implements OnInit { return this.nzTreeService.getHalfCheckedNodeList(); } - // ngModel + getExpandedNodeList(): NzTreeNode[] { + return this.nzTreeService.getExpandedNodeList(); + } + + getMatchedNodeList(): NzTreeNode[] { + return this.nzTreeService.getMatchedNodeList(); + } + + setClassMap(): void { + this.nzTreeClass = { + [ this.prefixCls ] : true, + [ this.prefixCls + '-show-line' ]: this.nzShowLine, + [ `${this.prefixCls}-icon-hide` ]: !this.nzShowIcon, + [ 'draggable-tree' ] : this.nzDraggable + }; + } + + // TODO: Deprecated writeValue(value: NzTreeNode[]): void { - if (value) { - this.ngModelNodes = value; - this.nzTreeService.initTreeNodes(this.ngModelNodes, this.nzDefaultCheckedKeys, this.nzCheckStrictly); - this.onChange(value); + if (Array.isArray(value) && value.length > 0) { + this.nzNodes = value; + this.nzTreeService.conductOption.isCheckStrictly = this.nzCheckStrictly; + this.nzTreeService.initTree(this.nzNodes); + } else { + if (value !== null) { + console.log('ngModel only accepts an array and should be not empty'); + } } } + // TODO: Deprecated registerOnChange(fn: (_: NzTreeNode[]) => void): void { this.onChange = fn; } + // TODO: Deprecated registerOnTouched(fn: () => void): void { this.onTouched = fn; } @@ -132,5 +219,32 @@ export class NzTreeComponent implements OnInit { } ngOnInit(): void { + this.setClassMap(); + this.nzDefaultSubscription = this.nzDefaultSubject.subscribe((data: { type: string, keys: string[] }) => { + if (data.keys.length === 0) { + return; + } + switch (data.type) { + case 'nzExpandedKeys': + this.nzTreeService.calcExpandedKeys(data.keys, this.nzNodes); + this.nzExpandedKeysChange.emit(data.keys); + break; + case 'nzSelectedKeys': + this.nzTreeService.calcSelectedKeys(data.keys, this.nzNodes, this.nzMultiple); + this.nzSelectedKeysChange.emit(data.keys); + break; + case 'nzCheckedKeys': + this.nzTreeService.calcCheckedKeys(data.keys, this.nzNodes, this.nzCheckStrictly); + this.nzCheckedKeysChange.emit(data.keys); + break; + } + }); + } + + ngOnDestroy(): void { + if (this.nzDefaultSubscription) { + this.nzDefaultSubscription.unsubscribe(); + this.nzDefaultSubscription = null; + } } } diff --git a/components/tree/nz-tree.module.ts b/components/tree/nz-tree.module.ts index 221c015df91..5578b979b5b 100644 --- a/components/tree/nz-tree.module.ts +++ b/components/tree/nz-tree.module.ts @@ -4,9 +4,19 @@ import { NzTreeNodeComponent } from './nz-tree-node.component'; import { NzTreeComponent } from './nz-tree.component'; @NgModule({ - imports : [ CommonModule ], - declarations: [ NzTreeComponent, NzTreeNodeComponent ], - exports : [ NzTreeComponent, NzTreeNodeComponent ] + imports : [ + CommonModule + ], + declarations: [ + NzTreeComponent, + NzTreeNodeComponent + ], + exports : [ + NzTreeComponent, + NzTreeNodeComponent + ] }) + export class NzTreeModule { + } diff --git a/components/tree/nz-tree.service.ts b/components/tree/nz-tree.service.ts index 827f39e1f2e..c806bc4ae77 100644 --- a/components/tree/nz-tree.service.ts +++ b/components/tree/nz-tree.service.ts @@ -1,309 +1,412 @@ import { Injectable } from '@angular/core'; - +import { isNotNil } from '../core/util/check'; import { NzFormatEmitEvent } from './interface'; import { NzTreeNode } from './nz-tree-node'; +import { isCheckDisabled, isInArray } from './nz-tree-util'; @Injectable() export class NzTreeService { DRAG_SIDE_RANGE = 0.25; DRAG_MIN_GAP = 2; + conductOption: { + isCheckStrictly: boolean + } = { + isCheckStrictly: false + }; selectedNode: NzTreeNode; targetNode: NzTreeNode; rootNodes: NzTreeNode[] = []; selectedNodeList: NzTreeNode[] = []; + expandedNodeList: NzTreeNode[] = []; checkedNodeList: NzTreeNode[] = []; halfCheckedNodeList: NzTreeNode[] = []; matchedNodeList: NzTreeNode[] = []; /** - * init data to NzTreeNode + * reset tree nodes will clear default node list */ - initCheckedStatus(childNode: NzTreeNode, defaultCheckedKeys: string[], nzCheckStrictly: boolean): void { - if (defaultCheckedKeys.indexOf(childNode.key) > -1) { - childNode.isChecked = true; - childNode.isAllChecked = true; - childNode.isHalfChecked = false; - } - if (childNode.getChildren()) { - childNode.getChildren().forEach((child) => { - // will change child status - if (!nzCheckStrictly && childNode.isChecked && !child.isDisabled && !child.isDisableCheckbox) { - child.isChecked = true; - child.isAllChecked = true; - child.isHalfChecked = false; - } - this.initCheckedStatus(child, defaultCheckedKeys, nzCheckStrictly); - }); - } + initTree(nzNodes: NzTreeNode[]): void { + this.rootNodes = nzNodes; + this.expandedNodeList = []; + this.selectedNodeList = []; + this.halfCheckedNodeList = []; + this.checkedNodeList = []; + this.expandedNodeList = []; + this.matchedNodeList = []; + setTimeout(() => { + this.refreshCheckState(this.conductOption.isCheckStrictly); + }); + } + + getSelectedNode(): NzTreeNode | null { + return this.selectedNode; + } + + /** + * get some list + */ + getSelectedNodeList(): NzTreeNode[] { + return this.selectedNodeList; + } + + /** + * return checked nodes + */ + getCheckedNodeList(): NzTreeNode[] { + return this.conductCheck('check'); + } + + getHalfCheckedNodeList(): NzTreeNode[] { + return this.conductCheck('halfCheck'); + } + + /** + * return expanded nodes + */ + getExpandedNodeList(): NzTreeNode[] { + return this.expandedNodeList; + } + + /** + * return search matched nodes + */ + getMatchedNodeList(): NzTreeNode[] { + return this.matchedNodeList; + } + + // tslint:disable-next-line:no-any + isArrayOfNzTreeNode(value: any[]): boolean { + return value.every(item => item instanceof NzTreeNode); } - initTreeNodes(root: NzTreeNode[], defaultCheckedKeys: string[] = [], nzCheckStrictly: boolean = false): NzTreeNode[] { - this.rootNodes = root; - if (root.length > 0) { - root.forEach((node) => { - this.initCheckedStatus(node, defaultCheckedKeys, nzCheckStrictly); + /** + * reset selectedNodeList + */ + calcSelectedKeys(selectedKeys: string[], nzNodes: NzTreeNode[], isMulti: boolean = false): void { + this.selectedNodeList = []; + const calc = (nodes: NzTreeNode[]) => { + nodes.forEach(node => { + if (isInArray(node.key, selectedKeys)) { + node.setSelected(true); + } else { + node.setSelected(false); + } + this.setSelectedNodeList(node, isMulti); + if (node.getChildren().length > 0) { + calc(node.getChildren()); + } }); - if (!nzCheckStrictly) { - root.forEach((node) => { - this.initParentNode(node); - }); - // should reset node status - } - } - return this.rootNodes; + }; + calc(nzNodes); + } /** - * init checkBox state + * reset expandedNodeList */ - initParentNode(node: NzTreeNode): void { - if (node.getChildren().length === 0) { - // until root - this.checkTreeNodeParents(node); - } else { - node.children.forEach((child) => { - this.initParentNode(child); + calcExpandedKeys(expandedKeys: string[], nzNodes: NzTreeNode[]): void { + this.expandedNodeList = []; + const calc = (nodes: NzTreeNode[]) => { + nodes.forEach(node => { + if (isInArray(node.key, expandedKeys)) { + node.setExpanded(true); + this.setExpandedNodeList(node); + } else { + node.setExpanded(false); + } + if (node.getChildren().length > 0) { + calc(node.getChildren()); + } }); - } + }; + calc(nzNodes); } /** - * 1、children half checked - * 2、children all checked, parent checked - * 3、no children checked + * reset checkedNodeList */ - checkTreeNodeParents(node: NzTreeNode): void { - const parentNode = node.getParentNode(); - // 全禁用节点不选中 - if (parentNode && (parentNode.isDisabled || parentNode.isDisableCheckbox)) { - if (parentNode.children.every(child => child.isDisabled || child.isDisableCheckbox)) { - return; - } - } - if (parentNode) { - if (parentNode.children.every(child => child.isDisabled || child.isDisableCheckbox || (!child.isHalfChecked && child.isAllChecked))) { - if (!(parentNode.isDisabled || parentNode.isDisableCheckbox)) { - parentNode.isChecked = true; - parentNode.isAllChecked = true; - parentNode.isHalfChecked = false; + calcCheckedKeys(checkedKeys: string[], nzNodes: NzTreeNode[], isCheckStrictly: boolean = false): void { + this.checkedNodeList = []; + this.halfCheckedNodeList = []; + const calc = (nodes: NzTreeNode[]) => { + nodes.forEach(node => { + if (isInArray(node.key, checkedKeys)) { + node.setChecked(true); + this.setCheckedNodeList(node); + } else { + node.setChecked(false); } - } else if (parentNode.children.some(child => child.isHalfChecked || child.isAllChecked)) { - if (!(parentNode.isDisabled || parentNode.isDisableCheckbox)) { - parentNode.isChecked = false; - parentNode.isAllChecked = false; - parentNode.isHalfChecked = true; + if (node.getChildren().length > 0) { + calc(node.getChildren()); } - } else { - parentNode.isChecked = false; - parentNode.isAllChecked = false; - parentNode.isHalfChecked = false; - } - this.checkTreeNodeParents(parentNode); - } + }); + }; + calc(nzNodes); + // controlled state + this.refreshCheckState(isCheckStrictly); } - setSelectedNode(node: NzTreeNode | null): void { - this.selectedNode = node; + /** + * set drag node + */ + setSelectedNode(node?: NzTreeNode): void { + this.selectedNode = null; + if (node) { + this.selectedNode = node; + } } - getSelectedNode(): NzTreeNode | null { - return this.selectedNode; + /** + * set node selected status + */ + setNodeActive(node: NzTreeNode, isMultiple: boolean = false): void { + const isSelected = node.isSelected; + if (node.isDisabled) { + return; + } + if (!isMultiple) { + this.selectedNodeList.forEach(n => { + n.setSelected(false); + }); + this.selectedNodeList = []; + } + node.setSelected(!isSelected); + this.setSelectedNodeList(node, isMultiple); } - // if node is clicked, add or remove node to select list - setSelectedNodeList(node: NzTreeNode, isMultiple: boolean): void { + /** + * add or remove node to selectedNodeList + */ + setSelectedNodeList(node: NzTreeNode, isMultiple: boolean = false): void { + const index = this.selectedNodeList.findIndex(n => node.key === n.key); if (isMultiple) { - const sIndex = this.selectedNodeList.findIndex(cNode => node.key === cNode.key); - if (node.isSelected && sIndex === -1) { + if (node.isSelected && index === -1) { this.selectedNodeList.push(node); - } else if (sIndex > -1 && !node.isSelected) { - this.selectedNodeList.splice(sIndex, 1); } } else { - if (node.isSelected) { + if (node.isSelected && index === -1) { this.selectedNodeList = [ node ]; - } else { - this.selectedNodeList = []; } } - } - - getSelectedNodeList(): NzTreeNode[] { - return this.selectedNodeList; + if (!node.isSelected && index > -1) { + this.selectedNodeList.splice(index, 1); + } } /** * merge checked nodes */ - setCheckedNodeListStrict(node: NzTreeNode): void { - if (node.isChecked && this.checkedNodeList.findIndex(cNode => (node.key === cNode.key)) === -1) { - this.checkedNodeList.push(node); - } else if (!node.isChecked && this.checkedNodeList.findIndex(cNode => (node.key === cNode.key)) > -1) { - // cancel checked - this.checkedNodeList.splice(this.checkedNodeList.findIndex(cNode => (node.key === cNode.key)), 1); + setHalfCheckedNodeList(node: NzTreeNode): void { + const index = this.halfCheckedNodeList.findIndex(n => node.key === n.key); + if (node.isHalfChecked && index === -1) { + this.halfCheckedNodeList.push(node); + } else if (!node.isHalfChecked && index > -1) { + this.halfCheckedNodeList.splice(index, 1); } } setCheckedNodeList(node: NzTreeNode): void { - if (node.isChecked && this.checkedNodeList.findIndex(cNode => (node.key === cNode.key)) === -1) { + const index = this.checkedNodeList.findIndex(n => node.key === n.key); + if (node.isChecked && index === -1) { this.checkedNodeList.push(node); + } else if (!node.isChecked && index > -1) { + this.checkedNodeList.splice(index, 1); } - const removeChild = (rNode: NzTreeNode) => { - const rIndex = this.checkedNodeList.findIndex(cNode => (rNode.key === cNode.key)); - if (rIndex > -1) { - this.checkedNodeList.splice(rIndex, 1); - } - rNode.children.forEach(child => { - removeChild(child); - }); - }; - // refresh tree nodes check state, merge child node checked - this.rootNodes.forEach((rNode: NzTreeNode) => { - const loopNode = (lNode: NzTreeNode) => { - const cIndex = this.checkedNodeList.findIndex(cNode => (lNode.key === cNode.key)); - if (lNode.isChecked) { - if (cIndex === -1) { - this.checkedNodeList.push(lNode); - } - // reset child state - lNode.children.forEach((child) => { - removeChild(child); - }); - } else { - if (cIndex > -1) { - this.checkedNodeList.splice(cIndex, 1); - } - lNode.children.forEach(child => { - loopNode(child); - }); - } - }; - loopNode(rNode); - }); - } - - /** - * return checked nodes - */ - getCheckedNodeList(): NzTreeNode[] { - return this.checkedNodeList; } /** - * return half checked nodes - * returns {NzTreeNode[]} + * conduct checked keys */ - getHalfCheckedNodeList(): NzTreeNode[] { - this.halfCheckedNodeList = []; - this.rootNodes.forEach((rNode: NzTreeNode) => { - const loopNode = (lNode: NzTreeNode) => { - const cIndex = this.halfCheckedNodeList.findIndex(cNode => (lNode.key === cNode.key)); - if (lNode.isHalfChecked) { - if (cIndex === -1) { - this.halfCheckedNodeList.push(lNode); + conductCheck(type: string = 'check'): NzTreeNode[] { + const checkedNodeList = []; + const loop = (node: NzTreeNode) => { + switch (type) { + case 'check': + if (node.isChecked) { + checkedNodeList.push(node); } - // reset child state - lNode.children.forEach((child) => { - loopNode(child); - }); - } - }; - loopNode(rNode); + if (!this.conductOption.isCheckStrictly) { + if (!node.isChecked) { + node.getChildren().forEach(child => { + loop(child); + }); + } + } else { + node.getChildren().forEach(child => { + loop(child); + }); + } + break; + case 'halfCheck': + if (!this.conductOption.isCheckStrictly) { + if (node.isHalfChecked) { + checkedNodeList.push(node); + node.getChildren().forEach(child => { + loop(child); + }); + } + } + break; + } + }; + this.rootNodes.forEach(node => { + loop(node); }); - return this.halfCheckedNodeList; + return checkedNodeList; } /** - * return search matched nodes + * set expanded nodes */ - getMatchedNodeList(): NzTreeNode[] { - return this.matchedNodeList; + setExpandedNodeList(node: NzTreeNode): void { + if (node.isLeaf) { + return; + } + const index = this.expandedNodeList.findIndex(n => node.key === n.key); + if (node.isExpanded && index === -1) { + this.expandedNodeList.push(node); + } else if (!node.isExpanded && index > -1) { + this.expandedNodeList.splice(index, 1); + } } /** - * keep selected state if isMultiple is true + * check state + * @param node */ - initNodeActive(node: NzTreeNode, isMultiple: boolean = false): void { - if (node.isDisabled) { + refreshCheckState(isCheckStrictly: boolean = false): void { + if (isCheckStrictly) { return; } - const isSelected = node.isSelected; - if (!isMultiple) { - this.rootNodes.forEach((child) => { - this.resetNodeActive(child); - }); - } - node.isSelected = !isSelected; - this.setSelectedNodeList(node, isMultiple); - } - // reset all nodes to unselected - resetNodeActive(node: NzTreeNode): void { - node.isSelected = false; - node.children.forEach((child) => { - this.resetNodeActive(child); + this.checkedNodeList.forEach(node => { + this.conduct(node); }); } + conduct(node: NzTreeNode): void { + const isChecked = node.isChecked; + if (node) { + this.conductUp(node); + this.conductDown(node, isChecked); + } + } + /** - * click checkbox + * 1、children half checked + * 2、children all checked, parent checked + * 3、no children checked */ - checkTreeNode(node: NzTreeNode): void { - this.checkTreeNodeChildren(node, node.isChecked); - this.checkTreeNodeParents(node); + conductUp(node: NzTreeNode): void { + const parentNode = node.getParentNode(); + // 全禁用节点不选中 + if (parentNode) { + if (!isCheckDisabled(parentNode)) { + if (parentNode.getChildren().every(child => isCheckDisabled(child) || (!child.isHalfChecked && child.isChecked))) { + parentNode.setChecked(true); + } else if (parentNode.getChildren().some(child => child.isHalfChecked || child.isChecked)) { + parentNode.setChecked(false, true); + } else { + parentNode.setChecked(false); + } + } + this.setHalfCheckedNodeList(parentNode); + this.conductUp(parentNode); + } } /** * reset child check state */ - checkTreeNodeChildren(node: NzTreeNode, value: boolean): void { - if (!node.isDisabled && !node.isDisableCheckbox) { - node.isChecked = value; - node.isAllChecked = value; - if (node.isChecked) { - node.isHalfChecked = false; - } - } - // 遍历全部子节点 - for (const n of node.children) { - this.checkTreeNodeChildren(n, value); + conductDown(node: NzTreeNode, value: boolean): void { + if (!isCheckDisabled(node)) { + node.setChecked(value); + node.children.forEach(n => { + this.conductDown(n, value); + }); } } /** - * search & expand node + * search value & expand node + * should add expandlist */ searchExpand(value: string): void { this.matchedNodeList = []; - if (!value) { + if (!isNotNil(value)) { return; } - const loopParent = (node: NzTreeNode) => { + // to reset expandedNodeList + this.expandedNodeList = []; + const expandParent = (p: NzTreeNode) => { // expand parent node - if (node.getParentNode()) { - node.getParentNode().isExpanded = true; - loopParent(node.getParentNode()); + if (p.getParentNode()) { + p.getParentNode().setExpanded(true); + this.setExpandedNodeList(p.getParentNode()); + expandParent(p.getParentNode()); } }; - const loopChild = (node: NzTreeNode) => { - if (value && node.title.includes(value)) { + const searchChild = (n: NzTreeNode) => { + if (value && n.title.includes(value)) { // match the node - this.matchedNodeList.push(node); + this.matchedNodeList.push(n); // expand parentNode - loopParent(node); + expandParent(n); } else { - node.isExpanded = false; + n.setExpanded(false); + this.setExpandedNodeList(n); } - node.children.forEach(cNode => { - loopChild(cNode); + n.children.forEach(g => { + searchChild(g); }); }; - this.rootNodes.forEach(node => { - loopChild(node); + this.rootNodes.forEach(child => { + searchChild(child); }); } + /** + * drag event + */ + refreshDragNode(node: NzTreeNode): void { + if (node.getChildren().length === 0) { + // until root + this.conductUp(node); + } else { + node.children.forEach((child) => { + this.refreshDragNode(child); + }); + } + } + + // reset node level + resetNodeLevel(node: NzTreeNode): void { + if (node.getParentNode()) { + node.level = node.getParentNode().level + 1; + } else { + node.level = 0; + } + for (const child of node.getChildren()) { + this.resetNodeLevel(child); + } + } + + calcDropPosition(event: DragEvent): number { + const { clientY } = event; + // to fix firefox undefined + const { top, bottom, height } = event.srcElement ? event.srcElement.getBoundingClientRect() : (event.target as Element).getBoundingClientRect(); + const des = Math.max(height * this.DRAG_SIDE_RANGE, this.DRAG_MIN_GAP); + + if (clientY <= top + des) { + return -1; + } else if (clientY >= bottom - des) { + return 1; + } + + return 0; + } + /** * drop * 0: inner -1: pre 1: next @@ -330,7 +433,9 @@ export class NzTreeService { const tIndex = dragPos === 1 ? 1 : 0; if (targetParent) { targetParent.addChildren([ this.selectedNode ], targetParent.children.indexOf(targetNode) + tIndex); - this.resetNodeLevel(this.selectedNode.getParentNode()); + if (this.selectedNode.getParentNode()) { + this.resetNodeLevel(this.selectedNode.getParentNode()); + } } else { const targetIndex = this.rootNodes.indexOf(targetNode) + tIndex; // 根节点插入 @@ -342,36 +447,10 @@ export class NzTreeService { } // flush all nodes this.rootNodes.forEach((child) => { - this.initParentNode(child); + this.refreshDragNode(child); }); } - // reset node level - resetNodeLevel(node: NzTreeNode): void { - if (node.getParentNode()) { - node.level = node.getParentNode().level + 1; - } else { - node.level = 0; - } - for (const child of node.getChildren()) { - this.resetNodeLevel(child); - } - } - - calcDropPosition(e: DragEvent): number { - const { clientY } = e; - const { top, bottom, height } = e.srcElement.getBoundingClientRect(); - const des = Math.max(height * this.DRAG_SIDE_RANGE, this.DRAG_MIN_GAP); - - if (clientY <= top + des) { - return -1; - } else if (clientY >= bottom - des) { - return 1; - } - - return 0; - } - /** * emit Structure * eventName @@ -395,15 +474,30 @@ export class NzTreeService { Object.assign(emitStructure, { 'dragNode': this.getSelectedNode() }); break; case 'click': + case 'dblclick': + // TODO: Deprecated Object.assign(emitStructure, { 'selectedKeys': this.getSelectedNodeList() }); + Object.assign(emitStructure, { 'nodes': this.getSelectedNodeList() }); + Object.assign(emitStructure, { 'keys': this.getSelectedNodeList().map(n => n.key) }); break; case 'check': + // TODO: Deprecated Object.assign(emitStructure, { 'checkedKeys': this.getCheckedNodeList() }); + Object.assign(emitStructure, { 'nodes': this.getCheckedNodeList() }); + Object.assign(emitStructure, { 'keys': this.getCheckedNodeList().map(n => n.key) }); break; case 'search': + // TODO: Deprecated Object.assign(emitStructure, { 'matchedKeys': this.getMatchedNodeList() }); + Object.assign(emitStructure, { 'nodes': this.getMatchedNodeList() }); + Object.assign(emitStructure, { 'keys': this.getMatchedNodeList().map(n => n.key) }); + break; + case 'expand': + Object.assign(emitStructure, { 'nodes': this.getExpandedNodeList() }); + Object.assign(emitStructure, { 'keys': this.getExpandedNodeList().map(n => n.key) }); break; } return emitStructure; } + } diff --git a/components/tree/nz-tree.spec.ts b/components/tree/nz-tree.spec.ts index 1fa19aca9b6..df91d73cea9 100644 --- a/components/tree/nz-tree.spec.ts +++ b/components/tree/nz-tree.spec.ts @@ -1,298 +1,334 @@ import { Component, ViewChild } from '@angular/core'; -import { async, fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, fakeAsync, tick, TestBed } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { of, Observable } from 'rxjs'; -import { dispatchMouseEvent, dispatchTouchEvent } from '../core/testing/dispatch-events'; +import { dispatchMouseEvent, dispatchTouchEvent } from '../core/testing'; import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from './interface'; import { NzTreeNode } from './nz-tree-node'; import { NzTreeComponent } from './nz-tree.component'; import { NzTreeModule } from './nz-tree.module'; import { NzTreeService } from './nz-tree.service'; -describe('tree component test', () => { +describe('nz-tree', () => { let treeInstance; - let fixture: ComponentFixture<{}>; + let treeElement: HTMLElement; + let component; + let fixture; let treeService: NzTreeService; - describe('basic tree', () => { - let treeElement: HTMLElement; beforeEach(async(() => { TestBed.configureTestingModule({ imports : [ NzTreeModule, NoopAnimationsModule, FormsModule, ReactiveFormsModule ], - declarations: [ NzDemoBasicTreeComponent ] + declarations: [ NzTestTreeBasicControlledComponent ] }).compileComponents(); - })); - - beforeEach(async(() => { - fixture = TestBed.createComponent(NzDemoBasicTreeComponent); + fixture = TestBed.createComponent(NzTestTreeBasicControlledComponent); + component = fixture.componentInstance; fixture.detectChanges(); treeInstance = fixture.debugElement.componentInstance; treeElement = fixture.debugElement.query(By.directive(NzTreeComponent)).nativeElement; })); - it('should create', () => { - expect(treeInstance).toBeTruthy(); + expect(component).toBeDefined(); }); - it('should className correct', fakeAsync(() => { - fixture.detectChanges(); - tick(100); - fixture.detectChanges(); - const allSelectedKeys = treeElement.querySelectorAll('.ant-tree-node-selected'); - expect(allSelectedKeys[ 0 ].getAttribute('title')).toEqual('child1'); - expect(allSelectedKeys[ 1 ].getAttribute('title')).toEqual('child1.1'); - expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(2); - // checked(child1 has disabled nodes) - const allCheckedKeys = treeElement.querySelectorAll('.ant-tree-checkbox-checked'); - expect(allCheckedKeys.length).toEqual(2); - // merged to one node + it('should set nzDefaultXXX correctly', fakeAsync(() => { + fixture.detectChanges(); + // checked expect(treeInstance.treeComponent.getCheckedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getCheckedNodeList()[ 0 ].title).toEqual('0-0-0'); + // half expanded + expect(treeInstance.treeComponent.getHalfCheckedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getHalfCheckedNodeList()[ 0 ].title).toEqual('0-0'); // expanded - const allExpandedKeys = treeElement.querySelectorAll('.ant-tree-switcher_open'); - expect(allExpandedKeys.length).toEqual(2); - })); + expect(treeInstance.treeComponent.getExpandedNodeList().length).toEqual(2); + // selected + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getSelectedNodeList()[ 0 ].title).toEqual('0-0-0-0'); - it('click should response correctly', fakeAsync(() => { + // won't affect + treeInstance.defaultExpandedKeys = []; fixture.detectChanges(); - tick(100); + tick(); fixture.detectChanges(); - const clickSpy = spyOn(treeInstance, 'onClick'); - // click child1 - let targetNode = treeElement.querySelectorAll('li')[ 1 ]; - expect(targetNode.querySelectorAll('.ant-tree-node-selected').length).toEqual(2); - dispatchMouseEvent(targetNode, 'click'); - fixture.detectChanges(); - // cancel selected - targetNode = treeElement.querySelectorAll('li')[ 1 ]; - expect(targetNode.querySelectorAll('.ant-tree-node-selected').length).toEqual(1); - expect(clickSpy).toHaveBeenCalled(); - expect(clickSpy).toHaveBeenCalledTimes(1); + expect(treeInstance.treeComponent.getExpandedNodeList().length).toEqual(2); + })); - it('dblclick/contextmenu should response correctly', fakeAsync(() => { + + it('test unCorrectly ngModel', () => { fixture.detectChanges(); - tick(100); + // TODO + // unsupported type, will console `ngModel only accepts an array and should be not empty` + treeInstance.nodes = 'string'; fixture.detectChanges(); - const clickSpy = spyOn(treeInstance, 'onClick'); - const dblClickSpy = spyOn(treeInstance, 'onDblClick'); - const contextMenuSpy = spyOn(treeInstance, 'onContextMenu'); - // detect changes + }); + + it('test new NzTreeNode of nzData', fakeAsync(() => { fixture.detectChanges(); - // dblclick child1 - let targetNode = treeElement.querySelectorAll('li')[ 1 ]; - dispatchMouseEvent(targetNode, 'dblclick'); + treeInstance.nodes = [ { + title : '0-0', + key : '0-0', + expanded: true, + children: [ { + title : '0-0-0', + key : '0-0-0', + expanded: true, + checked : true, + children: [ + { title: '0-0-0-0', key: '0-0-0-0', isLeaf: true }, + { title: '0-0-0-1', key: '0-0-0-1', isLeaf: true }, + { title: '0-0-0-2', key: '0-0-0-2', isLeaf: true } + ] + }, { + title : '0-0-1', + key : '0-0-1', + selected: true, + children: [ + { title: '0-0-1-0', key: '0-0-1-0', isLeaf: true }, + { title: '0-0-1-1', key: '0-0-1-1', isLeaf: true }, + { title: '0-0-1-2', key: '0-0-1-2', isLeaf: true } + ] + }, { + title : '0-0-2', + key : '0-0-2', + isLeaf: true + } ] + }, { + title : '0-1', + key : '0-1', + children: [ + { title: '0-1-0-0', key: '0-1-0-0', isLeaf: true }, + { title: '0-1-0-1', key: '0-1-0-1', isLeaf: true }, + { title: '0-1-0-2', key: '0-1-0-2', isLeaf: true } + ] + } ].map(v => { + return (new NzTreeNode(v)); + }); fixture.detectChanges(); - // cancel selected - expect(clickSpy).toHaveBeenCalledTimes(0); - // dblclick - expect(dblClickSpy).toHaveBeenCalled(); - expect(dblClickSpy).toHaveBeenCalledTimes(1); - // contextmenu - targetNode = treeElement.querySelectorAll('li')[ 1 ]; - dispatchMouseEvent(targetNode, 'contextmenu'); - expect(contextMenuSpy).toHaveBeenCalled(); - expect(contextMenuSpy).toHaveBeenCalledTimes(1); + tick(1000); + fixture.detectChanges(); + // reset node will clear default value except checked nodes list + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getExpandedNodeList().length).toEqual(2); + expect(treeInstance.treeComponent.getMatchedNodeList().length).toEqual(0); + // // checked nodes no effect + expect(treeInstance.treeComponent.getCheckedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getCheckedNodeList()[ 0 ].title).toEqual('0-0-0'); + + expect(treeInstance.treeComponent.getHalfCheckedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getHalfCheckedNodeList()[ 0 ].title).toEqual('0-0'); })); - it('check/expand should response correctly', fakeAsync(() => { - fixture.detectChanges(); - tick(100); + it('test click event', fakeAsync(() => { fixture.detectChanges(); - const checkSpy = spyOn(treeInstance, 'onCheck'); - const expandSpy = spyOn(treeInstance, 'onExpand'); - // detect changes + const clickSpy = spyOn(treeInstance, 'nzEvent'); + // click 0-0-0 to select + let targetNode = treeElement.querySelectorAll('nz-tree-node')[ 1 ]; + dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - // 2 checked in default(3 disabled not be contained) - expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(2); - // check child1 - let targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 0 ]; - expect(targetNode.classList).toContain('ant-tree-checkbox-indeterminate'); + // 0-0-0 / 0-0-0-0 are selected + expect(treeElement.querySelectorAll('.ant-tree-node-selected').length).toEqual(2); + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(2); + expect(clickSpy).toHaveBeenCalledTimes(1); + // cancel 0-0-0 selected dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 0 ]; - // all nodes inside root1 are checked(except 2 disabled) - expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(5); - expect(checkSpy).toHaveBeenCalledTimes(1); - // for bug test https://github.com/NG-ZORRO/ng-zorro-antd/issues/1423 - // auto merge child node - expect(treeInstance.treeComponent.getCheckedNodeList().length).toEqual(1); - expect(treeInstance.treeComponent.getCheckedNodeList()[ 0 ].title).toEqual('root1'); - // cancel checked status + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(1); + expect(clickSpy).toHaveBeenCalledTimes(2); + + // double click 0-0-0, only response once + targetNode = treeElement.querySelectorAll('nz-tree-node')[ 1 ]; + dispatchMouseEvent(targetNode, 'dblclick'); + fixture.detectChanges(); + // 0-0-0-0 are selected + expect(treeElement.querySelectorAll('.ant-tree-node-selected').length).toEqual(1); + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(1); + expect(clickSpy).toHaveBeenCalledTimes(3); // will detect dblclick + + // click disabled node + targetNode = treeElement.querySelectorAll('nz-tree-node')[ treeElement.querySelectorAll('nz-tree-node').length - 1 ]; dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); + expect(treeElement.querySelectorAll('.ant-tree-node-selected').length).toEqual(1); - // click node grandchild1.2.1 to test disabled node.(won't effect parent node) - targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 4 ]; + // set nzMultiple to false, click 0-0-0-0 will just active one node + treeInstance.multiple = false; + fixture.detectChanges(); + targetNode = treeElement.querySelectorAll('nz-tree-node')[ 0 ]; dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - expect(treeInstance.treeComponent.getCheckedNodeList().length).toEqual(1); + expect(treeElement.querySelectorAll('.ant-tree-node-selected').length).toEqual(1); + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(1); + expect(treeInstance.treeComponent.getSelectedNodeList()[ 0 ].title).toEqual('0-0'); + + // cancel selected + targetNode = treeElement.querySelectorAll('nz-tree-node')[ 0 ]; dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); + expect(treeElement.querySelectorAll('.ant-tree-node-selected').length).toEqual(0); + expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(0); + })); - expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(0); - expect(treeInstance.treeComponent.getCheckedNodeList().length).toEqual(0); - // test half checked nodes, click child1.1, just root1 halfchecked(child1 is full checked) - targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 2 ]; + it('test expand event', fakeAsync(() => { + fixture.detectChanges(); + // expand 0-0,now 3 nodes expanded + const targetNode = treeElement.querySelectorAll('.ant-tree-switcher')[ 0 ]; + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(2); dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - expect(treeInstance.treeComponent.getHalfCheckedNodeList().length).toEqual(1); - // // click disabled node - targetNode = treeElement.querySelector('.ant-tree-checkbox-disabled'); + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(3); + expect(treeElement.querySelectorAll('.ant-tree-switcher_open').length).toEqual(3); + })); + + it('test check event', fakeAsync(() => { + fixture.detectChanges(); + // uncheck 0-0-0 + let targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 1 ]; + expect(fixture.componentInstance.treeComponent.getCheckedNodeList().length).toEqual(1); dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - expect(targetNode.classList).toContain('ant-tree-checkbox-disabled'); + expect(fixture.componentInstance.treeComponent.getCheckedNodeList().length).toEqual(0); + expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(0); - // expand node - targetNode = treeElement.querySelectorAll('.ant-tree-switcher_close')[ 0 ]; + // check 0-0-0, will make 0-0 indeterminate + targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 1 ]; dispatchMouseEvent(targetNode, 'click'); + tick(300); fixture.detectChanges(); - expect(targetNode.classList).toContain('ant-tree-switcher_open'); - expect(expandSpy).toHaveBeenCalled(); - expect(expandSpy).toHaveBeenCalledTimes(1); + expect(fixture.componentInstance.treeComponent.getCheckedNodeList().length).toEqual(1); + expect(fixture.componentInstance.treeComponent.getHalfCheckedNodeList().length).toEqual(1); })); - it('should className correct showline/showexpand/expandall', fakeAsync(() => { - treeInstance.showLine = true; + it('test check event with nzCheckStrictly', fakeAsync(() => { fixture.detectChanges(); - tick(100); + treeInstance.checkStrictly = true; + treeInstance.nodes = [ + { + title : 'parent', + key : '0', + children: [ + { + title : 'child 1', + key : '0-0', + isLeaf: true + }, + { + title : 'child 2', + key : '0-1', + isLeaf: true + } + ] + } + ]; fixture.detectChanges(); - expect(treeElement.querySelector('ul').classList).toContain('ant-tree-show-line'); - // hide expand icon - expect(treeElement.querySelectorAll('.ant-tree-switcher').length).toBeGreaterThan(0); - treeInstance.showExpand = false; + tick(); fixture.detectChanges(); - expect(treeElement.querySelectorAll('.ant-tree-switcher').length).toEqual(0); - // expandAll - treeInstance.expandDefault = true; + // check node will not affect other nodes + let targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 0 ]; + dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - })); + expect(fixture.componentInstance.treeComponent.getCheckedNodeList().length).toEqual(1); + expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(1); - it('search value', () => { - const searchSpy = spyOn(treeInstance, 'onSearch'); - treeInstance.searchValue = 'grand'; + targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 1 ]; + dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - expect(treeElement.querySelectorAll('.font-highlight').length).toEqual(5); - expect(searchSpy).toHaveBeenCalled(); - expect(searchSpy).toHaveBeenCalledTimes(1); - }); - }); + expect(fixture.componentInstance.treeComponent.getCheckedNodeList().length).toEqual(2); + expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(2); - describe('async tree', () => { - treeInstance = null; - fixture = null; - let treeElement: HTMLElement; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports : [ NzTreeModule, NoopAnimationsModule, FormsModule, ReactiveFormsModule ], - declarations: [ NzDemoAsyncTreeComponent ] - }).compileComponents(); })); - beforeEach(fakeAsync(() => { - fixture = TestBed.createComponent(NzDemoAsyncTreeComponent); - treeInstance = fixture.debugElement.componentInstance; - treeElement = fixture.debugElement.query(By.directive(NzTreeComponent)).nativeElement; + it('test contextmenu event', fakeAsync(() => { fixture.detectChanges(); + const clickSpy = spyOn(treeInstance, 'nzEvent'); + // contextmenu 0-0-0 + const targetNode = treeElement.querySelectorAll('nz-tree-node')[ 1 ]; + dispatchMouseEvent(targetNode, 'contextmenu'); + fixture.detectChanges(); + expect(clickSpy).toHaveBeenCalledTimes(1); })); - it('should create', () => { - expect(treeInstance).toBeTruthy(); - }); - - it('should add children', () => { - const expandSpy = spyOn(treeInstance, 'onExpand'); - // detect changes + it('test disabled node check event', fakeAsync(() => { fixture.detectChanges(); - // init - expect(treeElement.querySelectorAll('.ant-tree-switcher').length).toEqual(3); - // click expand, test can not excute add children - const targetNode = treeElement.querySelectorAll('.ant-tree-switcher')[ 0 ]; + const clickSpy = spyOn(treeInstance, 'nzEvent'); + // contextmenu 0-0-0 + const targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ treeElement.querySelectorAll('li').length - 1 ]; dispatchMouseEvent(targetNode, 'click'); fixture.detectChanges(); - expect(expandSpy).toHaveBeenCalled(); - expect(expandSpy).toHaveBeenCalledTimes(1); - }); - }); - - describe('test node', () => { - let treeNode: NzTreeNode; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ NzTreeModule ] - }).compileComponents(); + expect(clickSpy).toHaveBeenCalledTimes(0); })); - beforeEach(fakeAsync(() => { - treeNode = new NzTreeNode({ - title : 'root1', - key : '1001', - children: [] - }); + it('test expand all node', fakeAsync(() => { + fixture.detectChanges(); + fixture.componentInstance.expandAll = true; + tick(); + fixture.detectChanges(); + // all parent node will be expanded + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(4); })); - it('should create', () => { - expect(treeNode).toBeDefined(); - }); - - it('should add children', () => { - // add json array - treeNode.addChildren([ - { - title: 'childAdd-1', - key : '10031-' + (new Date()).getTime() - }, - { - title : 'childAdd-2', - key : '10032-' + (new Date()).getTime(), - isLeaf: true - } ]); - expect(treeNode.getChildren().length).toEqual(2); - // add NzTreeNode - treeNode.clearChildren(); - const newNode = new NzTreeNode({ - title: 'childAdd-1', - key : '100001' - }); - treeNode.addChildren([ newNode ]); - expect(treeNode.getChildren().length).toEqual(1); - expect(treeNode.getChildren()[ 0 ].title).toEqual('childAdd-1'); - }); + it('test search value', fakeAsync(() => { + fixture.detectChanges(); + fixture.componentInstance.searchValue = '0-0'; + fixture.detectChanges(); + // matched node's parent node will be expanded + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(4); + expect(fixture.componentInstance.treeComponent.getMatchedNodeList().length).toEqual(11); + expect(treeElement.querySelectorAll('.font-highlight').length).toEqual(11); + })); - it('add children if node is leaf', () => { - treeNode = new NzTreeNode({ - title : 'root1', - key : '1001', - isLeaf: true - }); - treeNode.addChildren([ { - title: 'childAdd-1', - key : '100001' + it('test async loading', fakeAsync(() => { + fixture.detectChanges(); + fixture.componentInstance.asyncData = true; + treeInstance.nodes = [ + { title: 'Expand to load', key: '0' }, + { title: 'Expand to load', key: '1' }, + { title: 'Tree Node', key: '2', isLeaf: true } + ]; + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + let targetNode = treeElement.querySelectorAll('.ant-tree-switcher')[ 0 ]; + dispatchMouseEvent(targetNode, 'click'); + tick(); + fixture.detectChanges(); + expect(treeElement.querySelectorAll('.ant-tree-treenode-loading').length).toEqual(1); + expect(treeElement.querySelectorAll('.ant-tree-switcher_open').length).toEqual(1); + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(1); + // add children to clear loading state + fixture.componentInstance.treeComponent.getExpandedNodeList()[ 0 ].addChildren([ { + title: 'Child Node', + key : `0-0` } ]); - expect(treeNode.getChildren().length).toEqual(0); - }); + fixture.detectChanges(); + expect(treeElement.querySelectorAll('.ant-tree-treenode-loading').length).toEqual(0); + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(1); - it('init node with children', () => { - treeNode = new NzTreeNode({ - title : 'root1', - key : '1001', - checked : true, - children: [ { - title: 'childAdd-1', - key : '100001' - } ] - }); - expect(treeNode.getChildren().length).toEqual(1); - expect(treeNode.getChildren()[ 0 ].isChecked).toEqual(true); - }); + // add nzTreeNode children to clear loading state + targetNode = treeElement.querySelectorAll('.ant-tree-switcher')[ 2 ]; + dispatchMouseEvent(targetNode, 'click'); + tick(); + fixture.detectChanges(); + // getExpandedNodeList return ['0', '1'] + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(2); + expect(treeElement.querySelectorAll('.ant-tree-treenode-loading').length).toEqual(1); + fixture.componentInstance.treeComponent.getExpandedNodeList()[ 1 ].addChildren([ new NzTreeNode({ + title: 'Child Node', + key : `1-0` + }) ]); + fixture.detectChanges(); + expect(treeElement.querySelectorAll('.ant-tree-treenode-loading').length).toEqual(0); + expect(treeElement.querySelectorAll('.ant-tree-switcher_open').length).toEqual(2); + expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(2); + })); }); describe('test draggable node', () => { - let treeElement: HTMLElement; beforeEach(async(() => { TestBed.configureTestingModule({ imports : [ NzTreeModule, NoopAnimationsModule, FormsModule, ReactiveFormsModule ], - declarations: [ NzDemoDraggableTreeComponent ], + declarations: [ NzTestTreeDraggableComponent ], providers : [ NzTreeService ] @@ -300,18 +336,19 @@ describe('tree component test', () => { })); beforeEach(async(() => { - fixture = TestBed.createComponent(NzDemoDraggableTreeComponent); + fixture = TestBed.createComponent(NzTestTreeDraggableComponent); + component = fixture.componentInstance; + treeService = fixture.componentInstance.treeComponent.nzTreeService; + fixture.detectChanges(); treeInstance = fixture.debugElement.componentInstance; treeElement = fixture.debugElement.query(By.directive(NzTreeComponent)).nativeElement; - fixture.detectChanges(); })); it('should create', () => { expect(treeInstance).toBeTruthy(); }); - it('drag event', fakeAsync(() => { - fixture.detectChanges(); - tick(100); + + it('test drag event', fakeAsync(() => { fixture.detectChanges(); const dragStartSpy = spyOn(treeInstance, 'onDragStart'); const dragEnterSpy = spyOn(treeInstance, 'onDragEnter'); @@ -319,405 +356,224 @@ describe('tree component test', () => { const dragLeaveSpy = spyOn(treeInstance, 'onDragLeave'); const dropSpy = spyOn(treeInstance, 'onDrop'); const dragEndSpy = spyOn(treeInstance, 'onDragEnd'); - - let dragNode = treeElement.querySelector('[title=root3]'); // root3 - let dropNode = treeElement.querySelector('[title=root1]'); // root1 - let passNode = treeElement.querySelector('[title=root2]'); // root2 + let dragNode = treeElement.querySelector('[title=\'0-1\']'); + let dropNode = treeElement.querySelector('[title=\'0-0\']'); + let passNode = treeElement.querySelector('[title=\'0-0-0\']'); dispatchTouchEvent(dragNode, 'dragstart'); - dispatchTouchEvent(passNode, 'dragenter'); + dispatchTouchEvent(dropNode, 'dragenter'); fixture.detectChanges(); + // drag - dragenter - dragNode = treeElement.querySelector('[title=root3]'); // root3 - passNode = treeElement.querySelector('[title=root2]'); // root2 + dragNode = treeElement.querySelector('[title=\'0-1\']'); + dropNode = treeElement.querySelector('[title=\'0-0\']'); expect(dragNode.previousElementSibling.classList).toContain('ant-tree-switcher_close'); - expect(passNode.previousElementSibling.classList).toContain('ant-tree-switcher_open'); + expect(dropNode.previousElementSibling.classList).toContain('ant-tree-switcher_open'); expect(dragStartSpy).toHaveBeenCalledTimes(1); expect(dragEnterSpy).toHaveBeenCalledTimes(1); + // dragover dispatchTouchEvent(passNode, 'dragover'); fixture.detectChanges(); - passNode = treeElement.querySelector('[title=root2]'); // root2 + passNode = treeElement.querySelector('[title=\'0-0-0\']'); expect(passNode.parentElement.classList).toContain('drag-over'); expect(dragOverSpy).toHaveBeenCalledTimes(1); + // dragleave dispatchTouchEvent(passNode, 'dragleave'); fixture.detectChanges(); - passNode = treeElement.querySelector('[title=root2]'); // root2 + passNode = treeElement.querySelector('[title=\'0-0-0\']'); expect(passNode.parentElement.classList.contains('drag-over')).toEqual(false); expect(dragLeaveSpy).toHaveBeenCalledTimes(1); - // drop root3 to root1 - dispatchTouchEvent(dropNode, 'dragover'); + + // drop 0-1 to 0-0 dispatchTouchEvent(dropNode, 'drop'); fixture.detectChanges(); + dropNode = treeElement.querySelector('[title=\'0-0\']'); expect(dropSpy).toHaveBeenCalledTimes(1); - dropNode = treeElement.querySelector('[title=root1]'); - expect(dropNode.parentElement.querySelector('[title=root3]')).toBeDefined(); + expect(dropNode.parentElement.querySelector('[title=\'0-1\']')).toBeDefined(); + // dragend dispatchTouchEvent(dropNode, 'dragend'); fixture.detectChanges(); expect(dragEndSpy).toHaveBeenCalledTimes(1); - })); - it('drag event canDrop', () => { - treeInstance.beforeDrop = (arg: NzFormatBeforeDropEvent): Observable => { - return of(true); - }; - fixture.detectChanges(); - const dropSpy = spyOn(treeInstance, 'onDrop'); - - const dragNode = treeElement.querySelector('[title=root3]'); // root3 - let dropNode = treeElement.querySelector('[title=root1]'); // root1 + // drag 0-0 child node to 0-1 + dragNode = treeElement.querySelector('[title=\'0-0-0\']'); + dropNode = treeElement.querySelector('[title=\'0-1\']'); dispatchTouchEvent(dragNode, 'dragstart'); - fixture.detectChanges(); - // drop root3 to root1 + dispatchTouchEvent(dropNode, 'dragover'); dispatchTouchEvent(dropNode, 'drop'); fixture.detectChanges(); - expect(dropSpy).toHaveBeenCalledTimes(1); - dropNode = treeElement.querySelector('[title=root1]'); - expect(dropNode.parentElement.querySelector('[title=root3]')).toBeDefined(); - }); - }); - - describe('test service', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports : [ NzTreeModule, NoopAnimationsModule, FormsModule, ReactiveFormsModule ], - declarations: [ NzDemoDraggableTreeComponent ], - providers : [ - NzTreeService - ] - }).compileComponents(); + dropNode = treeElement.querySelector('[title=\'0-1\']'); + expect(dropSpy).toHaveBeenCalledTimes(2); + expect(dropNode.parentElement.querySelector('[title=\'0-0-0\']')).toBeDefined(); })); - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoDraggableTreeComponent); - treeInstance = fixture.debugElement.componentInstance; - treeService = treeInstance.nzTreeService; - treeService.initTreeNodes(treeInstance.nodes); - }); - it('test service - setSelectedNodeList', () => { - const selectedNode = treeService.rootNodes[ 0 ]; - // node is not selected - treeService.setSelectedNodeList(selectedNode, false); - // node is already selected - selectedNode.isSelected = true; - treeService.setSelectedNodeList(selectedNode, false); - }); - - it('test service - initNodeActive', () => { - const selectedNode = treeService.rootNodes[ 0 ]; - selectedNode.isDisabled = true; - treeService.initNodeActive(selectedNode, false); - expect(treeService.getSelectedNodeList().length).toEqual(0); - selectedNode.isDisabled = false; - treeService.initNodeActive(selectedNode, false); - expect(treeService.getSelectedNodeList().length).toEqual(1); - expect(treeService.getSelectedNodeList()[ 0 ].title).toEqual('root1'); - }); - - it('test service - dropAndApply', () => { + // can not dispatchTouchEvent with pos, test alone + it('test drag drop with dragPos', () => { // init selected node - treeService.selectedNode = treeService.rootNodes[ 0 ].getChildren()[ 0 ]; // child1 - // drop - // dragPos = 2, not drop - let targetNode = treeService.rootNodes[ 2 ]; // root3 - treeService.dropAndApply(targetNode, 2); - // dragPos = -1, pre + treeService = treeInstance.treeComponent.nzTreeService; + const dragNode = treeElement.querySelectorAll('li')[ 1 ]; + dispatchTouchEvent(dragNode, 'dragstart'); + fixture.detectChanges(); + // drop 0-0-0 to 0-0 pre + let targetNode = treeService.rootNodes[ 0 ]; // 0-0 treeService.dropAndApply(targetNode, -1); - expect(treeService.rootNodes[ 2 ].level).toEqual(0); - expect(treeService.rootNodes[ 2 ].title).toEqual('child1'); - // dragPos = -1, next - treeService.selectedNode = treeService.rootNodes[ 2 ]; // child1 - targetNode = treeService.rootNodes[ 3 ]; + expect(treeService.rootNodes[ 0 ].title).toEqual('0-0-0'); + expect(treeService.rootNodes[ 0 ].level).toEqual(0); + + // drop 0-0-0 to 0-0-1 next + treeService.selectedNode = treeService.rootNodes[ 0 ]; + targetNode = treeService.rootNodes[ 1 ].getChildren()[ 0 ]; // 0-0-1 treeService.dropAndApply(targetNode, 1); - expect(treeService.rootNodes[ 3 ].title).toEqual('child1'); - }); + expect(treeService.rootNodes[ 0 ].getChildren()[ 1 ].title).toEqual('0-0-0'); + expect(treeService.rootNodes[ 0 ].getChildren()[ 1 ].level).toEqual(1); - it('test service - dropAndApply - has - parent', () => { - // init selected node - treeService.selectedNode = treeService.rootNodes[ 0 ].getChildren()[ 0 ]; // child1 - // drop to child2.2 pre - const targetNode = treeService.rootNodes[ 1 ].getChildren()[ 1 ]; // child2.2 - treeService.dropAndApply(targetNode, -1); - expect(treeService.rootNodes[ 1 ].getChildren()[ 1 ].title).toEqual('child1'); + // drop 0-0-1 to 0-0-0 next + treeService.selectedNode = treeService.rootNodes[ 0 ].getChildren()[ 0 ]; + targetNode = treeService.rootNodes[ 0 ].getChildren()[ 1 ]; // 0-0-1 + treeService.dropAndApply(targetNode, 1); + expect(treeService.rootNodes[ 0 ].getChildren()[ 0 ].title).toEqual('0-0-0'); }); - }); - describe('strict mode', () => { - treeInstance = null; - fixture = null; - let treeElement: HTMLElement; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports : [ NzTreeModule, NoopAnimationsModule, FormsModule, ReactiveFormsModule ], - declarations: [ NzDemoStrictTreeComponent ] - }).compileComponents(); - })); + it('test wrong drag event', fakeAsync(() => { + // drop node self + fixture.detectChanges(); + const dragStartSpy = spyOn(treeInstance, 'onDragStart'); + const dropSpy = spyOn(treeInstance, 'onDrop'); + const dragEndSpy = spyOn(treeInstance, 'onDragEnd'); + const dragNode = treeElement.querySelector('[title=\'0-1\']'); + let dropNode = treeElement.querySelector('[title=\'0-2\']'); - beforeEach(fakeAsync(() => { - fixture = TestBed.createComponent(NzDemoStrictTreeComponent); - treeInstance = fixture.debugElement.componentInstance; - treeElement = fixture.debugElement.query(By.directive(NzTreeComponent)).nativeElement; + // drop 0-1 to 0-2(leaf node) + dispatchTouchEvent(dragNode, 'dragstart'); + dispatchTouchEvent(dropNode, 'dragover'); + dispatchTouchEvent(dropNode, 'drop'); fixture.detectChanges(); - tick(1000); + dropNode = treeElement.querySelector('[title=\'0-2\']'); + expect(dropSpy).toHaveBeenCalledTimes(0); + expect(dropNode.parentElement.querySelector('[title=\'0-1\']')).toBeNull(); + // dragend + dispatchTouchEvent(dropNode, 'dragend'); fixture.detectChanges(); + expect(dragEndSpy).toHaveBeenCalledTimes(1); + // drop to itself + dispatchTouchEvent(dragNode, 'dragstart'); + dispatchTouchEvent(dragNode, 'dragover'); + dispatchTouchEvent(dragNode, 'drop'); + fixture.detectChanges(); + expect(dropSpy).toHaveBeenCalledTimes(0); + // dragend + dispatchTouchEvent(dropNode, 'dragend'); + fixture.detectChanges(); + expect(dragEndSpy).toHaveBeenCalledTimes(2); })); - it('should create', () => { - expect(treeInstance).toBeTruthy(); - }); - - it('should check strictly', () => { - fixture.detectChanges(); - // check child1 - let targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 0 ]; - dispatchMouseEvent(targetNode, 'click'); + it('test drag event nzBeforeDrop', () => { + const dropSpy = spyOn(treeInstance, 'onDrop'); + const dragNode = treeElement.querySelector('[title=\'0-2\']'); + let dropNode = treeElement.querySelector('[title=\'0-1\']'); + treeInstance.beforeDrop = (arg: NzFormatBeforeDropEvent): Observable => { + return of(true); + }; fixture.detectChanges(); - expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(2); - // cancel - targetNode = treeElement.querySelectorAll('.ant-tree-checkbox')[ 0 ]; - dispatchMouseEvent(targetNode, 'click'); + + dispatchTouchEvent(dragNode, 'dragstart'); + dispatchTouchEvent(dropNode, 'dragover'); + // drop 0-2 to 0-1 + dispatchTouchEvent(dropNode, 'drop'); fixture.detectChanges(); - expect(treeElement.querySelectorAll('.ant-tree-checkbox-checked').length).toEqual(1); + dropNode = treeElement.querySelector('[title=\'0-1\']'); + expect(dropNode.parentElement.querySelector('[title=\'0-2\']')).toBeDefined(); }); + }); -}); -// ------------------------------------------- -// | Testing Components -// ------------------------------------------- -@Component({ - selector: 'nz-demo-tree-strict', - template: ` - - - ` -}) -class NzDemoStrictTreeComponent { - checkedKeys = [ '100011' ]; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - checked : true, - children: [] - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - }, - { - title: 'child2', - key : '10002' - } - ] - }) - ]; -} +}); @Component({ - selector: 'nz-demo-tree-basic', + selector: 'nz-test-tree-basic-controlled', template: ` + [nzExpandAll]="expandAll" + [nzAsyncData]="asyncData" + (nzSearchValueChange)="nzEvent($event)" + (nzClick)="nzEvent($event)" + (nzDblClick)="nzEvent($event)" + (nzContextMenu)="nzEvent($event)" + (nzExpandChange)="nzEvent($event)" + (nzCheckBoxChange)="nzEvent($event)"> ` }) -class NzDemoBasicTreeComponent { - @ViewChild(NzTreeComponent) treeComponent: NzTreeComponent; - expandKeys = [ '1001', '10001' ]; - checkedKeys = [ '10001' ]; - selectedKeys = [ '10001', '100011' ]; + +export class NzTestTreeBasicControlledComponent { + @ViewChild('treeComponent') treeComponent: NzTreeComponent; + searchValue; multiple = true; - expandDefault = false; - showLine = false; - showExpand = true; - searchValue = ''; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', + expandAll = false; + asyncData = false; + checkStrictly = false; + defaultCheckedKeys = [ '0-0-0' ]; + defaultSelectedKeys = [ '0-0-0-0' ]; + defaultExpandedKeys = [ '0-0-0', '0-0-1' ]; + + nodes = [ { + title : '0-0', + key : '0-0', + expanded: true, + children: [ { + title : '0-0-0', + key : '0-0-0', children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - children: [] - }, - { - title : 'child1.2', - key : '100012', - disabled: true, - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf : true, - disableCheckbox: true - } - ] - } - ] - }, - { - title: 'child2', - key : '10002' - } + { title: '0-0-0-0', key: '0-0-0-0', isLeaf: true }, + { title: '0-0-0-1', key: '0-0-0-1', isLeaf: true }, + { title: '0-0-0-2', key: '0-0-0-2', isLeaf: true } ] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', + }, { + title : '0-0-1', + key : '0-0-1', children: [ - { - title : 'child2.1', - key : '10021', - disableCheckbox: true, - children : [ - { - title : 'grandchild2.1.1', - key : '100211', - isLeaf : true, - disableCheckbox: true - }, - { - title : 'grandchild2.1.2', - key : '1002112', - isLeaf : true, - disableCheckbox: true - } - ] - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title: 'grandchild2.2.1', - key : '100221' - } - ] - } + { title: '0-0-1-0', key: '0-0-1-0', isLeaf: true }, + { title: '0-0-1-1', key: '0-0-1-1', isLeaf: true }, + { title: '0-0-1-2', key: '0-0-1-2', isLeaf: true } ] - }), - new NzTreeNode({ title: 'root3', key: '1003' }) - ]; - - onClick(): void { - } - - onDblClick(): void { - } - - onContextMenu(): void { - } - - onCheck(): void { - } - - onExpand(): void { - } - - onSearch(): void { + }, { + title : '0-0-2', + key : '0-0-2', + isLeaf: true + } ] + }, { + title : '0-1', + key : '0-1', + children: [ + { title: '0-1-0-0', key: '0-1-0-0', isLeaf: true }, + { title: '0-1-0-1', key: '0-1-0-1', isLeaf: true }, + { title: '0-1-0-2', key: '0-1-0-2', isLeaf: true } + ] + }, { + title : '0-2', + key : '0-2', + disabled: true, + isLeaf : true + } ]; + + nzEvent(event: NzFormatEmitEvent): void { + // console.log(event.eventName, event); } } -// ------------------------------------------- -// | Testing Async Components -// ------------------------------------------- - -@Component({ - selector: 'nz-demo-tree-async', - template: ` - - `, - styles : [] -}) - -class NzDemoAsyncTreeComponent { - @ViewChild(NzTreeComponent) treeComponent: NzTreeComponent; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', - children: [] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', - children: [] - }), - new NzTreeNode({ - title: 'root3', - key : '1003' - }) - ]; - - onExpand(data: NzFormatEmitEvent): void { - } -} - // ------------------------------------------- // | Testing Draggable Components // ------------------------------------------- @@ -726,107 +582,88 @@ class NzDemoAsyncTreeComponent { selector: 'nz-demo-tree-draggable', template: ` - `, - styles : [] + (nzOnDragStart)="onDragStart($event)" + (nzOnDragEnter)="onDragEnter($event)" + (nzOnDragLeave)="onDragLeave($event)" + (nzOnDragOver)="onDragOver($event)" + (nzOnDrop)="onDrop($event)" + (nzOnDragEnd)="onDragEnd($event)"> + + ` }) -class NzDemoDraggableTreeComponent { +export class NzTestTreeDraggableComponent { @ViewChild(NzTreeComponent) treeComponent: NzTreeComponent; - nodes = [ - new NzTreeNode({ - title : 'root1', - key : '1001', + nodes = [ { + title : '0-0', + key : '00', + expanded: true, + children: [ { + title : '0-0-0', + key : '000', + expanded: true, children: [ - { - title : 'child1', - key : '10001', - children: [ - { - title : 'child1.1', - key : '100011', - children: [] - }, - { - title : 'child1.2', - key : '100012', - children: [ - { - title : 'grandchild1.2.1', - key : '1000121', - isLeaf : true, - disabled: true - }, - { - title : 'grandchild1.2.2', - key : '1000122', - isLeaf: true - } - ] - } - ] - }, - { - title: 'child2', - key : '10002' - } + { title: '0-0-0-0', key: '0000', isLeaf: true }, + { title: '0-0-0-1', key: '0001', isLeaf: true }, + { title: '0-0-0-2', key: '0002', isLeaf: true } ] - }), - new NzTreeNode({ - title : 'root2', - key : '1002', + }, { + title : '0-0-1', + key : '001', children: [ - { - title : 'child2.1', - key : '10021', - children : [], - disableCheckbox: true - }, - { - title : 'child2.2', - key : '10022', - children: [ - { - title: 'grandchild2.2.1', - key : '100221' - } - ] - } + { title: '0-0-1-0', key: '0010', isLeaf: true }, + { title: '0-0-1-1', key: '0011', isLeaf: true }, + { title: '0-0-1-2', key: '0012', isLeaf: true } ] - }), - new NzTreeNode({ title: 'root3', key: '1003', expanded: true }) - ]; - + }, { + title: '0-0-2', + key : '002' + } ] + }, { + title : '0-1', + key : '01', + children: [ { + title : '0-1-0', + key : '010', + children: [ + { title: '0-1-0-0', key: '0100', isLeaf: true }, + { title: '0-1-0-1', key: '0101', isLeaf: true }, + { title: '0-1-0-2', key: '0102', isLeaf: true } + ] + }, { + title : '0-1-1', + key : '011', + children: [ + { title: '0-1-1-0', key: '0110', isLeaf: true }, + { title: '0-1-1-1', key: '0111', isLeaf: true }, + { title: '0-1-1-2', key: '0112', isLeaf: true } + ] + } ] + }, { + title : '0-2', + key : '02', + isLeaf: true + } ]; beforeDrop; - onDragStart(): void { - } - - onDragEnter(): void { + onDragStart(event: NzFormatEmitEvent): void { } - onDragOver(): void { + onDragEnter(event: NzFormatEmitEvent): void { } - onDragLeave(): void { + onDragOver(event: NzFormatEmitEvent): void { } - onDrop(): void { + onDragLeave(event: NzFormatEmitEvent): void { } - onDragEnd(): void { + onDrop(event: NzFormatEmitEvent): void { } - constructor(public nzTreeService: NzTreeService) { + onDragEnd(event: NzFormatEmitEvent): void { } } diff --git a/components/tree/public-api.ts b/components/tree/public-api.ts index 7c2c06d5a2b..ab361136129 100644 --- a/components/tree/public-api.ts +++ b/components/tree/public-api.ts @@ -1,6 +1,7 @@ export * from './interface'; +export * from './nz-tree.module'; export * from './nz-tree.component'; export * from './nz-tree-node.component'; export * from './nz-tree-node'; export * from './nz-tree.service'; -export * from './nz-tree.module'; +export * from './nz-tree-util';