From 050faa0ba0962d57ae8baa05e447b85dabfe12d4 Mon Sep 17 00:00:00 2001 From: simplejason Date: Mon, 4 Mar 2019 16:28:28 +0800 Subject: [PATCH] fix(module: tree): fix default keys bug with setTimeOut (#3003) close #3001 fix(module: tree): remove unused code fix(module: tree): fix tree spec test fix(module: tree): fix tree demo fix(module: tree): fix tree drag event and remove unsave code fix(module: tree-select): remove code comments fix(module: tree): fix demo --- .../tree-select/nz-tree-select.component.ts | 5 +- components/tree-select/nz-tree-select.spec.ts | 2 + components/tree/demo/basic.ts | 16 +- components/tree/demo/customized-icon.ts | 2 +- components/tree/demo/directory.ts | 16 +- components/tree/demo/draggable.ts | 12 +- components/tree/demo/dynamic.ts | 2 +- components/tree/demo/line.ts | 2 +- components/tree/demo/search.ts | 4 +- components/tree/doc/index.en-US.md | 5 - components/tree/doc/index.zh-CN.md | 5 - components/tree/nz-tree-base.service.ts | 90 ++++--- components/tree/nz-tree-node.component.html | 20 +- components/tree/nz-tree-node.component.ts | 166 ++++++------- components/tree/nz-tree-node.ts | 232 ++++++++++++------ components/tree/nz-tree.component.html | 16 +- components/tree/nz-tree.component.ts | 80 +++++- components/tree/nz-tree.spec.ts | 59 +++-- 18 files changed, 431 insertions(+), 303 deletions(-) diff --git a/components/tree-select/nz-tree-select.component.ts b/components/tree-select/nz-tree-select.component.ts index 5961a5b558..cd44e46635 100644 --- a/components/tree-select/nz-tree-select.component.ts +++ b/components/tree-select/nz-tree-select.component.ts @@ -250,7 +250,7 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, OnDe if (this.selectedNodes.length) { const removeNode = this.selectedNodes[ this.selectedNodes.length - 1 ]; this.removeSelected(removeNode); - this.nzTreeService.$statusChange.next({ + this.nzTreeService.triggerEventChange$.next({ 'eventName': 'removeSelect', 'node' : removeNode }); @@ -274,7 +274,6 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, OnDe node.isChecked = false; if (this.nzCheckable) { this.nzTreeService.conduct(node); - this.nzTreeService.setCheckedNodeList(node); } else { this.nzTreeService.setSelectedNodeList(node, this.nzMultiple); } @@ -305,7 +304,6 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, OnDe if (this.nzCheckable && !node.isDisabled && !node.isDisableCheckbox) { node.isChecked = !node.isChecked; this.nzTreeService.conduct(node); - this.nzTreeService.setCheckedNodeList(node); } if (this.nzCheckable) { node.isSelected = false; @@ -341,6 +339,7 @@ export class NzTreeSelectComponent implements ControlValueAccessor, OnInit, OnDe updateSelectedNodes(init: boolean = false): void { if (init) { let nodes; + this.nzTreeService.isMultiple = this.isMultiple; if (!this.nzTreeService.isArrayOfNzTreeNode(this.nzNodes)) { // has not been new NzTreeNode nodes = this.nzNodes.map(item => (new NzTreeNode(item, null, this.nzTreeService))); diff --git a/components/tree-select/nz-tree-select.spec.ts b/components/tree-select/nz-tree-select.spec.ts index f47fbb1783..4063baf9d8 100644 --- a/components/tree-select/nz-tree-select.spec.ts +++ b/components/tree-select/nz-tree-select.spec.ts @@ -212,7 +212,9 @@ describe('tree-select component', () => { expect(selectedValueEl.style.opacity).toBe('1'); })); it('should max tag count work', fakeAsync(() => { + fixture.detectChanges(); testComponent.multiple = true; + fixture.detectChanges(); testComponent.value = [ '1001', '10001', '100011', '100012' ]; fixture.detectChanges(); tick(200); diff --git a/components/tree/demo/basic.ts b/components/tree/demo/basic.ts index 1704fbbd4d..aa3d8587b2 100644 --- a/components/tree/demo/basic.ts +++ b/components/tree/demo/basic.ts @@ -1,5 +1,5 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { NzFormatEmitEvent, NzTreeNodeOptions } from 'ng-zorro-antd'; +import { NzFormatEmitEvent, NzTreeNodeOptions, NzTreeComponent } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-basic', @@ -7,21 +7,21 @@ import { NzFormatEmitEvent, NzTreeNodeOptions } from 'ng-zorro-antd'; + (nzCheckBoxChange)="nzCheck($event)" + (nzExpandChange)="nzCheck($event)"> ` }) export class NzDemoTreeBasicComponent implements OnInit { - @ViewChild('treeCom') treeCom; - defaultCheckedKeys = [ '1001', '1002' ]; - defaultSelectedKeys = [ '10010', '10020' ]; + @ViewChild('treeCom') treeCom: NzTreeComponent; + defaultCheckedKeys = [ '10020' ]; + defaultSelectedKeys = [ '10010' ]; defaultExpandedKeys = [ '100', '1001' ]; nodes: NzTreeNodeOptions[] = [ { @@ -33,7 +33,7 @@ export class NzDemoTreeBasicComponent implements OnInit { 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: 'leaf 1-0-1', key: '10011', isLeaf: true } ] }, { title : 'parent 1-1', @@ -50,7 +50,7 @@ export class NzDemoTreeBasicComponent implements OnInit { } nzCheck(event: NzFormatEmitEvent): void { - console.log(event, event.checkedKeys, event.keys, event.nodes); + console.log(event); } // nzSelectedKeys change diff --git a/components/tree/demo/customized-icon.ts b/components/tree/demo/customized-icon.ts index f6d8077e6f..12d4d9a185 100644 --- a/components/tree/demo/customized-icon.ts +++ b/components/tree/demo/customized-icon.ts @@ -5,7 +5,7 @@ import { Component, OnInit } from '@angular/core'; template: ` + nzShowIcon> ` }) diff --git a/components/tree/demo/directory.ts b/components/tree/demo/directory.ts index a86871ea98..dbbacf1662 100644 --- a/components/tree/demo/directory.ts +++ b/components/tree/demo/directory.ts @@ -13,11 +13,12 @@ import { + (nzClick)="activeNode($event)" + (nzDblClick)="openFolder($event)">
    -
  • 新建文件
  • -
  • 新建文件夹
  • +
  • Action 1
  • +
  • Action 2
@@ -27,7 +28,7 @@ import { {{node.title}} created by {{node?.origin?.author | lowercase}} - + {{node.title}} modified by {{node?.origin?.author | lowercase}} @@ -102,14 +103,13 @@ export class NzDemoTreeDirectoryComponent { openFolder(data: NzTreeNode | NzFormatEmitEvent): void { // do something if u want if (data instanceof NzTreeNode) { - data.setExpanded(!data.isExpanded); + data.isExpanded = !data.isExpanded; } else { - data.node.setExpanded(!data.node.isExpanded); + data.node.isExpanded = !data.node.isExpanded; } } activeNode(data: NzFormatEmitEvent): void { - data.node.setExpanded(true); this.activedNode = data.node; } @@ -117,7 +117,7 @@ export class NzDemoTreeDirectoryComponent { this.dropdown = this.nzDropdownService.create($event, template); } - selectDropdown(_type: string): void { + selectDropdown(): void { this.dropdown.close(); // do something } diff --git a/components/tree/demo/draggable.ts b/components/tree/demo/draggable.ts index 70cd6bdd9b..4a324ff063 100644 --- a/components/tree/demo/draggable.ts +++ b/components/tree/demo/draggable.ts @@ -1,11 +1,14 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { NzFormatEmitEvent, NzTreeComponent } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-draggable', template: ` + nzDraggable + (nzOnDrop)="nzEvent($event)"> `, styles : [ ` @@ -16,6 +19,7 @@ import { Component, OnInit } from '@angular/core'; }) export class NzDemoTreeDraggableComponent implements OnInit { + @ViewChild('treeCom') treeCom: NzTreeComponent; nodes = [ { title : '0-0', key : '00', @@ -67,6 +71,10 @@ export class NzDemoTreeDraggableComponent implements OnInit { isLeaf: true } ]; + nzEvent(event: NzFormatEmitEvent): void { + console.log(event); + } + ngOnInit(): void { } } diff --git a/components/tree/demo/dynamic.ts b/components/tree/demo/dynamic.ts index 57926ad123..d02c700a1d 100644 --- a/components/tree/demo/dynamic.ts +++ b/components/tree/demo/dynamic.ts @@ -6,7 +6,7 @@ import { NzFormatEmitEvent } from 'ng-zorro-antd'; template: ` diff --git a/components/tree/demo/line.ts b/components/tree/demo/line.ts index 596f85fba1..40c74ca8e7 100644 --- a/components/tree/demo/line.ts +++ b/components/tree/demo/line.ts @@ -6,7 +6,7 @@ import { NzFormatEmitEvent } from 'ng-zorro-antd'; template: ` ` diff --git a/components/tree/demo/search.ts b/components/tree/demo/search.ts index ac2cd4337a..385fb5f0fe 100644 --- a/components/tree/demo/search.ts +++ b/components/tree/demo/search.ts @@ -1,5 +1,5 @@ import { Component, OnInit, ViewChild } from '@angular/core'; -import { NzFormatEmitEvent } from 'ng-zorro-antd'; +import { NzFormatEmitEvent, NzTreeComponent } from 'ng-zorro-antd'; @Component({ selector: 'nz-demo-tree-search', @@ -27,7 +27,7 @@ import { NzFormatEmitEvent } from 'ng-zorro-antd'; }) export class NzDemoTreeSearchComponent implements OnInit { - @ViewChild('treeCom') treeCom; + @ViewChild('treeCom') treeCom: NzTreeComponent; searchValue; nodes = [ { diff --git a/components/tree/doc/index.en-US.md b/components/tree/doc/index.en-US.md index 1432f28c7c..afe692cc48 100644 --- a/components/tree/doc/index.en-US.md +++ b/components/tree/doc/index.en-US.md @@ -110,7 +110,6 @@ Almost anything can be represented in a tree structure. Examples include directo | isDisableCheckbox | Whether treeNode's checkbox can not be clicked | `boolean` | `true` / `false` | | isSelectable | Set whether the treeNode can be selected | `boolean` | `true` 或 `false` | | isChecked | Whether treeNode is checked | `boolean` | `true` / `false` | -| isAllChecked | Whether all treeNode's children are checked | `boolean` | `true` / `false` | | isHalfChecked | Part of treeNode's children are checked | `boolean` | `true` / `false` | | isSelected | Whether treeNode is selected | `boolean` | `true` / `false` | | isLoading | Whether treeNode is loading(when nzAsyncData is true) | `boolean` | `true` / `false` | @@ -119,10 +118,6 @@ Almost anything can be represented in a tree structure. Examples include directo | 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 | | remove | Clear current node(not root node) | function | void | -| setSyncChecked | set isChecked & isHalfChecked state,params: checked , halfChecked.(will affect other nodes checked state) | (checked: boolean, halfChecked: boolean=false)=>{} | 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 27ee641f58..2158281460 100644 --- a/components/tree/doc/index.zh-CN.md +++ b/components/tree/doc/index.zh-CN.md @@ -114,7 +114,6 @@ subtitle: 树形控件 | isDisableCheckbox | 是否禁用 checkBox | `boolean` | `true` 或 `false` | | isSelectable | 是否可选中 | `boolean` | `true` 或 `false` | | isChecked | 是否选中 checkBox | `boolean` | `true` 或 `false` | -| isAllChecked | 子节点是否全选 | `boolean` | `true` 或 `false` | | isHalfChecked | 子节点有选中但未全选 | `boolean` | `true` 或 `false` | | isSelected | 是否已选中 | `boolean` | `true` 或 `false` | | isLoading | 是否异步加载状态(影响展开图标展示) | `boolean` | `true` 或 `false` | @@ -123,10 +122,6 @@ subtitle: 树形控件 | addChildren | 添加子节点,接收NzTreeNode或NzTreeNodeOptions数组,第二个参数为插入的索引位置,默认插入末尾 | (children: array, index?: number )=>{} | void | | clearChildren | 清除子节点 | function | void | | remove | 清除当前节点(非根节点) | function | void | -| setSyncChecked | 设置checked状态(同步树组件节点 checked 状态) | (checked: boolean, halfChecked: boolean=false)=>{} | void | -| setChecked | 设置checked状态,参数为checked和halfChecked | (checked: boolean, halfChecked: boolean=false)=>{} | void | -| setExpanded | 设置expanded状态 | (value: boolean)=>{} | void | -| setSelected | 设置selected状态 | (value: boolean)=>{} | void | ## 注意 diff --git a/components/tree/nz-tree-base.service.ts b/components/tree/nz-tree-base.service.ts index 2d3f113b21..68e60a15c8 100644 --- a/components/tree/nz-tree-base.service.ts +++ b/components/tree/nz-tree-base.service.ts @@ -19,10 +19,13 @@ export class NzTreeBaseService implements OnDestroy { checkedNodeList: NzTreeNode[] = []; halfCheckedNodeList: NzTreeNode[] = []; matchedNodeList: NzTreeNode[] = []; - $statusChange = new Subject(); + triggerEventChange$ = new Subject(); - statusChanged(): Observable { - return this.$statusChange.asObservable(); + /** + * trigger event + */ + eventTriggerChanged(): Observable { + return this.triggerEventChange$.asObservable(); } /** @@ -89,17 +92,17 @@ export class NzTreeBaseService implements OnDestroy { const calc = (nodes: NzTreeNode[]): boolean => { return nodes.every(node => { if (isInArray(node.key, selectedKeys)) { - node.setSelected(true, isMulti); + node.isSelected = true; if (!isMulti) { // if not support multi select return false; } } else { - node.setSelected(false, isMulti); + node.isSelected = false; } - if (node.getChildren().length > 0) { + if (node.children.length > 0) { // Recursion - return calc(node.getChildren()); + return calc(node.children); } return true; }); @@ -115,13 +118,12 @@ export class NzTreeBaseService implements OnDestroy { const calc = (nodes: NzTreeNode[]) => { nodes.forEach(node => { if (isInArray(node.key, expandedKeys)) { - node.setExpanded(true); - this.setExpandedNodeList(node); + node.isExpanded = true; } else { - node.setExpanded(false); + node.isExpanded = false; } - if (node.getChildren().length > 0) { - calc(node.getChildren()); + if (node.children.length > 0) { + calc(node.children); } }); }; @@ -137,12 +139,14 @@ export class NzTreeBaseService implements OnDestroy { const calc = (nodes: NzTreeNode[]) => { nodes.forEach(node => { if (isInArray(node.key, checkedKeys)) { - node.setChecked(true); + node.isChecked = true; + node.isHalfChecked = false; } else { - node.setChecked(false); + node.isChecked = false; + node.isHalfChecked = false; } - if (node.getChildren().length > 0) { - calc(node.getChildren()); + if (node.children.length > 0) { + calc(node.children); } }); }; @@ -164,26 +168,25 @@ export class NzTreeBaseService implements OnDestroy { /** * set node selected status */ - setNodeActive(node: NzTreeNode, isMultiple: boolean = false): void { - if (!isMultiple && node.isSelected) { + setNodeActive(node: NzTreeNode): void { + if (!this.isMultiple && node.isSelected) { this.selectedNodeList.forEach(n => { if (node.key !== n.key) { // reset other nodes - n.origin.selected = false; n.isSelected = false; } }); // single mode: remove pre node this.selectedNodeList = []; } - this.setSelectedNodeList(node, isMultiple); + this.setSelectedNodeList(node, this.isMultiple); } /** * add or remove node to selectedNodeList */ setSelectedNodeList(node: NzTreeNode, isMultiple: boolean = false): void { - const index = this.selectedNodeList.findIndex(n => node.key === n.key); + let index = this.selectedNodeList.findIndex(n => node.key === n.key); if (isMultiple) { if (node.isSelected && index === -1) { this.selectedNodeList.push(node); @@ -193,6 +196,7 @@ export class NzTreeBaseService implements OnDestroy { this.selectedNodeList = [ node ]; } } + index = this.selectedNodeList.findIndex(n => node.key === n.key); if (!node.isSelected && index > -1) { this.selectedNodeList.splice(index, 1); } @@ -288,6 +292,7 @@ export class NzTreeBaseService implements OnDestroy { }); } + // reset other node checked state based current node conduct(node: NzTreeNode): void { const isChecked = node.isChecked; if (node) { @@ -306,14 +311,19 @@ export class NzTreeBaseService implements OnDestroy { // 全禁用节点不选中 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); + if (parentNode.children.every(child => isCheckDisabled(child) || (!child.isHalfChecked && child.isChecked))) { + parentNode.isChecked = true; + parentNode.isHalfChecked = false; + } else if (parentNode.children.some(child => child.isHalfChecked || child.isChecked)) { + parentNode.isChecked = false; + parentNode.isHalfChecked = true; } else { - parentNode.setChecked(false); + parentNode.isChecked = false; + parentNode.isHalfChecked = false; } } + this.setCheckedNodeList(parentNode); + this.setHalfCheckedNodeList(parentNode); this.conductUp(parentNode); } } @@ -323,7 +333,10 @@ export class NzTreeBaseService implements OnDestroy { */ conductDown(node: NzTreeNode, value: boolean): void { if (!isCheckDisabled(node)) { - node.setChecked(value); + node.isChecked = value; + node.isHalfChecked = false; + this.setCheckedNodeList(node); + this.setHalfCheckedNodeList(node); node.children.forEach(n => { this.conductDown(n, value); }); @@ -358,7 +371,7 @@ export class NzTreeBaseService implements OnDestroy { } else { n.isMatched = false; } - n.getChildren().forEach(child => { + n.children.forEach(child => { searchChild(child); }); }; @@ -392,8 +405,8 @@ export class NzTreeBaseService implements OnDestroy { this.checkedNodeList.splice(index, 1); } - if (n.getChildren()) { - n.getChildren().forEach(child => { + if (n.children) { + n.children.forEach(child => { loopNode(child); }); } @@ -408,11 +421,11 @@ export class NzTreeBaseService implements OnDestroy { * drag event */ refreshDragNode(node: NzTreeNode): void { - if (node.getChildren().length === 0) { + if (node.children.length === 0) { // until root this.conductUp(node); } else { - node.getChildren().forEach((child) => { + node.children.forEach((child) => { this.refreshDragNode(child); }); } @@ -425,7 +438,7 @@ export class NzTreeBaseService implements OnDestroy { } else { node.level = 0; } - for (const child of node.getChildren()) { + for (const child of node.children) { this.resetNodeLevel(child); } } @@ -453,11 +466,12 @@ export class NzTreeBaseService implements OnDestroy { if (!targetNode || dragPos > 1) { return; } + const treeService = targetNode.treeService; const targetParent = targetNode.getParentNode(); const isSelectedRootNode = this.selectedNode.getParentNode(); // remove the dragNode if (isSelectedRootNode) { - isSelectedRootNode.getChildren().splice(isSelectedRootNode.getChildren().indexOf(this.selectedNode), 1); + isSelectedRootNode.children.splice(isSelectedRootNode.children.indexOf(this.selectedNode), 1); } else { this.rootNodes.splice(this.rootNodes.indexOf(this.selectedNode), 1); } @@ -485,6 +499,9 @@ export class NzTreeBaseService implements OnDestroy { } // flush all nodes this.rootNodes.forEach((child) => { + if (!child.treeService) { + child.service = treeService; + } this.refreshDragNode(child); }); } @@ -519,6 +536,7 @@ export class NzTreeBaseService implements OnDestroy { break; case 'check': const checkedNodeList = this.getCheckedNodeList(); + Object.assign(emitStructure, { 'checkedKeys': checkedNodeList }); Object.assign(emitStructure, { 'nodes': checkedNodeList }); Object.assign(emitStructure, { 'keys': checkedNodeList.map(n => n.key) }); @@ -537,8 +555,8 @@ export class NzTreeBaseService implements OnDestroy { } ngOnDestroy(): void { - this.$statusChange.complete(); - this.$statusChange = null; + this.triggerEventChange$.complete(); + this.triggerEventChange$ = null; } } diff --git a/components/tree/nz-tree-node.component.html b/components/tree/nz-tree-node.component.html index 00f2dfe56f..bb61f6f82d 100644 --- a/components/tree/nz-tree-node.component.html +++ b/components/tree/nz-tree-node.component.html @@ -37,14 +37,14 @@ [ngClass]="nzNodeContentClass" [class.draggable]="canDraggable"> - + @@ -72,7 +72,7 @@ [@.disabled]="noAnimation?.nzNoAnimation" [@collapseMotion]="nzTreeNode.isExpanded ? 'expanded' : 'collapsed'"> + [nzTreeTemplate]="nzTreeTemplate"> \ No newline at end of file diff --git a/components/tree/nz-tree-node.component.ts b/components/tree/nz-tree-node.component.ts index 7d6ee2c1fd..1960ed4453 100644 --- a/components/tree/nz-tree-node.component.ts +++ b/components/tree/nz-tree-node.component.ts @@ -3,7 +3,6 @@ import { ChangeDetectorRef, Component, ElementRef, - EventEmitter, Host, HostListener, Input, @@ -12,20 +11,18 @@ import { OnDestroy, OnInit, Optional, - Output, Renderer2, TemplateRef, ViewChild } from '@angular/core'; import { fromEvent, Observable, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { filter, takeUntil } from 'rxjs/operators'; import { collapseMotion } from '../core/animation/collapse'; import { NzNoAnimationDirective } from '../core/no-animation/nz-no-animation.directive'; import { InputBoolean } from '../core/util/convert'; -import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from '../tree/interface'; +import { NzFormatBeforeDropEvent } from '../tree/interface'; import { NzTreeBaseService } from './nz-tree-base.service'; import { NzTreeNode } from './nz-tree-node'; -import { isCheckDisabled } from './nz-tree-util'; @Component({ selector : 'nz-tree-node', @@ -38,9 +35,12 @@ import { isCheckDisabled } from './nz-tree-util'; export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { @ViewChild('dragElement') dragElement: ElementRef; + /** + * for global property + */ + @Input() nzTreeNode: NzTreeNode; @Input() @InputBoolean() nzShowLine: boolean; @Input() @InputBoolean() nzShowExpand: boolean; - @Input() @InputBoolean() nzMultiple: boolean; @Input() @InputBoolean() nzCheckable: boolean; @Input() @InputBoolean() nzAsyncData: boolean; @Input() @InputBoolean() nzCheckStrictly: boolean; @@ -51,26 +51,6 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { @Input() nzTreeTemplate: TemplateRef; @Input() nzBeforeDrop: (confirm: NzFormatBeforeDropEvent) => Observable; - @Input() - set nzTreeNode(value: NzTreeNode) { - // add to checked list & selected list - if (value.isChecked) { - this.nzTreeService.setCheckedNodeList(value); - } - // add select list - if (value.isSelected) { - value.setSelected(true, this.nzMultiple); - } - if (!value.isLeaf) { - this.nzTreeService.setExpandedNodeList(value); - } - this._nzTreeNode = value; - } - - get nzTreeNode(): NzTreeNode { - return this._nzTreeNode; - } - @Input() set nzDraggable(value: boolean) { this._nzDraggable = value; @@ -89,7 +69,7 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { set nzDefaultExpandAll(value: boolean) { this._nzExpandAll = value; if (value && this.nzTreeNode && !this.nzTreeNode.isLeaf) { - this.nzTreeNode.setExpanded(true); + this.nzTreeNode.isExpanded = true; } } @@ -102,7 +82,7 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { set nzExpandAll(value: boolean) { this._nzExpandAll = value; if (value && this.nzTreeNode && !this.nzTreeNode.isLeaf) { - this.nzTreeNode.setExpanded(true); + this.nzTreeNode.isExpanded = true; } } @@ -116,8 +96,7 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { if (value && this.nzTreeNode.title.includes(value)) { // match the search value const index = this.nzTreeNode.title.indexOf(value); - this.highlightKeys.push(this.nzTreeNode.title.slice(0, index)); - this.highlightKeys.push(this.nzTreeNode.title.slice(index + value.length, this.nzTreeNode.title.length)); + this.highlightKeys = [ this.nzTreeNode.title.slice(0, index), this.nzTreeNode.title.slice(index + value.length, this.nzTreeNode.title.length) ]; } this._searchValue = value; } @@ -126,19 +105,6 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { return this._searchValue; } - // Output - @Output() readonly clickNode: EventEmitter = new EventEmitter(); - @Output() readonly dblClick: EventEmitter = new EventEmitter(); - @Output() readonly contextMenu: EventEmitter = new EventEmitter(); - @Output() readonly clickCheckBox: EventEmitter = new EventEmitter(); - @Output() readonly clickExpand: EventEmitter = new EventEmitter(); - @Output() readonly nzDragStart: EventEmitter = new EventEmitter(); - @Output() readonly nzDragEnter: EventEmitter = new EventEmitter(); - @Output() readonly nzDragOver: EventEmitter = new EventEmitter(); - @Output() readonly nzDragLeave: EventEmitter = new EventEmitter(); - @Output() readonly nzDrop: EventEmitter = new EventEmitter(); - @Output() readonly nzDragEnd: EventEmitter = new EventEmitter(); - // default var prefixCls = 'ant-tree'; highlightKeys = []; @@ -163,21 +129,16 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { /** * default set */ - _nzTreeNode: NzTreeNode; _searchValue = ''; - _nzExpandAll = false; _nzDraggable = false; - oldAPIIcon = true; + _nzExpandAll = false; get nzIcon(): string { - if (this.nzTreeNode && this.nzTreeNode.origin.icon) { - this.oldAPIIcon = this.nzTreeNode.origin.icon.indexOf('anticon') > -1; - } - return this.nzTreeNode && this.nzTreeNode.origin.icon; + return this.nzTreeNode.icon; } get canDraggable(): boolean | null { - return (this.nzDraggable && this.nzTreeNode && !this.nzTreeNode.isDisabled) ? true : null; + return (this.nzDraggable && !this.nzTreeNode.isDisabled) ? true : null; } get isShowLineIcon(): boolean { @@ -201,10 +162,6 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { return (this.nzSearchValue && this.nzHideUnMatched && !this.nzTreeNode.isMatched && !this.nzTreeNode.isExpanded) ? 'none' : ''; } - trackByFn = (_index: number, item: NzTreeNode) => { - return item.key; - } - /** * reset node class */ @@ -262,19 +219,19 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { nzClick(event: MouseEvent): void { event.preventDefault(); event.stopPropagation(); - if (this.nzTreeNode.isSelectable) { - this.nzTreeNode.setSelected(!this.nzTreeNode.isSelected, this.nzMultiple); + if (this.nzTreeNode.isSelectable && !this.nzTreeNode.isDisabled) { + this.nzTreeNode.isSelected = !this.nzTreeNode.isSelected; } - const clickEvent = this.nzTreeService.formatEvent('click', this.nzTreeNode, event); - this.clickNode.emit(clickEvent); - this.nzTreeService.$statusChange.next(clickEvent); + const eventNext = this.nzTreeService.formatEvent('click', this.nzTreeNode, event); + this.nzTreeService.triggerEventChange$.next(eventNext); } @HostListener('dblclick', [ '$event' ]) nzDblClick(event: MouseEvent): void { event.preventDefault(); event.stopPropagation(); - this.dblClick.emit(this.nzTreeService.formatEvent('dblclick', this.nzTreeNode, event)); + const eventNext = this.nzTreeService.formatEvent('dblclick', this.nzTreeNode, event); + this.nzTreeService.triggerEventChange$.next(eventNext); } /** @@ -284,7 +241,8 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { nzContextMenu(event: MouseEvent): void { event.preventDefault(); event.stopPropagation(); - this.contextMenu.emit(this.nzTreeService.formatEvent('contextmenu', this.nzTreeNode, event)); + const eventNext = this.nzTreeService.formatEvent('contextmenu', this.nzTreeNode, event); + this.nzTreeService.triggerEventChange$.next(eventNext); } /** @@ -296,14 +254,12 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { event.stopPropagation(); if (!this.nzTreeNode.isLoading && !this.nzTreeNode.isLeaf) { // set async state - if (this.nzAsyncData && this.nzTreeNode.getChildren().length === 0 && !this.nzTreeNode.isExpanded) { + if (this.nzAsyncData && this.nzTreeNode.children.length === 0 && !this.nzTreeNode.isExpanded) { this.nzTreeNode.isLoading = true; } - this.nzTreeNode.setExpanded(!this.nzTreeNode.isExpanded); - const expandEvent = this.nzTreeService.formatEvent('expand', this.nzTreeNode, event); - this.clickExpand.emit(expandEvent); - // just affect self - this.setClassMap(); + this.nzTreeNode.isExpanded = !this.nzTreeNode.isExpanded; + const eventNext = this.nzTreeService.formatEvent('expand', this.nzTreeNode, event); + this.nzTreeService.triggerEventChange$.next(eventNext); } } @@ -315,13 +271,16 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { event.preventDefault(); event.stopPropagation(); // return if node is disabled - if (isCheckDisabled(this.nzTreeNode)) { + if (this.nzTreeNode.isDisabled || this.nzTreeNode.isDisableCheckbox) { return; } - this.nzTreeNode.setSyncChecked(!this.nzTreeNode.isChecked); - const checkBoxChangeEvent = this.nzTreeService.formatEvent('check', this.nzTreeNode, event); - this.clickCheckBox.emit(checkBoxChangeEvent); - this.nzTreeService.$statusChange.next(checkBoxChangeEvent); + this.nzTreeNode.isChecked = !this.nzTreeNode.isChecked; + this.nzTreeNode.isHalfChecked = false; + if (!this.nzTreeService.isCheckStrictly) { + this.nzTreeService.conduct(this.nzTreeNode); + } + const eventNext = this.nzTreeService.formatEvent('check', this.nzTreeNode, event); + this.nzTreeService.triggerEventChange$.next(eventNext); } /** @@ -340,13 +299,14 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { try { // ie throw error // firefox-need-it - e.dataTransfer.setData('text/plain', ''); + e.dataTransfer.setData('text/plain', this.nzTreeNode.key); } catch (error) { // empty } this.nzTreeService.setSelectedNode(this.nzTreeNode); - this.nzTreeNode.setExpanded(false); - this.nzDragStart.emit(this.nzTreeService.formatEvent('dragstart', null, e)); + this.nzTreeNode.isExpanded = false; + const eventNext = this.nzTreeService.formatEvent('dragstart', this.nzTreeNode, e); + this.nzTreeService.triggerEventChange$.next(eventNext); } handleDragEnter(e: DragEvent): void { @@ -355,13 +315,13 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { // reset position this.dragPos = 2; this.ngZone.run(() => { - if ((this.nzTreeNode !== this.nzTreeService.getSelectedNode()) && !this.nzTreeNode.isLeaf) { - this.nzTreeNode.setExpanded(true); + const node = this.nzTreeService.getSelectedNode(); + if (node && node.key !== this.nzTreeNode.key && !this.nzTreeNode.isExpanded && !this.nzTreeNode.isLeaf) { + this.nzTreeNode.isExpanded = true; } + const eventNext = this.nzTreeService.formatEvent('dragenter', this.nzTreeNode, e); + this.nzTreeService.triggerEventChange$.next(eventNext); }); - const dragEnterEvent = this.nzTreeService.formatEvent('dragenter', this.nzTreeNode, e); - this.nzDragEnter.emit(dragEnterEvent); - this.nzTreeService.$statusChange.next(dragEnterEvent); } handleDragOver(e: DragEvent): void { @@ -376,7 +336,8 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { this.renderer.addClass(this.dragElement.nativeElement, this.dragPosClass[ this.dragPos ]); } } - this.nzDragOver.emit(this.nzTreeService.formatEvent('dragover', this.nzTreeNode, e)); + const eventNext = this.nzTreeService.formatEvent('dragover', this.nzTreeNode, e); + this.nzTreeService.triggerEventChange$.next(eventNext); } handleDragLeave(e: DragEvent): void { @@ -384,7 +345,8 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { this.ngZone.run(() => { this.clearDragClass(); }); - this.nzDragLeave.emit(this.nzTreeService.formatEvent('dragleave', this.nzTreeNode, e)); + const eventNext = this.nzTreeService.formatEvent('dragleave', this.nzTreeNode, e); + this.nzTreeService.triggerEventChange$.next(eventNext); } handleDragDrop(e: DragEvent): void { @@ -392,9 +354,8 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { e.stopPropagation(); this.ngZone.run(() => { this.clearDragClass(); - if (this.nzTreeService.getSelectedNode() === this.nzTreeNode) { - return; - } else if (this.dragPos === 0 && this.nzTreeNode.isLeaf) { + const node = this.nzTreeService.getSelectedNode(); + if (!node || (node && node.key === this.nzTreeNode.key) || (this.dragPos === 0 && this.nzTreeNode.isLeaf)) { return; } // pass if node is leafNo @@ -409,14 +370,12 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { if (canDrop) { this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos); } - this.nzDrop.emit(dropEvent); - this.nzDragEnd.emit(dragEndEvent); - this.nzTreeService.$statusChange.next(dropEvent); + this.nzTreeService.triggerEventChange$.next(dropEvent); + this.nzTreeService.triggerEventChange$.next(dragEndEvent); }); } else if (this.nzTreeNode) { this.nzTreeService.dropAndApply(this.nzTreeNode, this.dragPos); - this.nzDrop.emit(dropEvent); - this.nzTreeService.$statusChange.next(dropEvent); + this.nzTreeService.triggerEventChange$.next(dropEvent); } }); } @@ -427,8 +386,8 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { // if user do not custom beforeDrop if (!this.nzBeforeDrop) { this.nzTreeService.setSelectedNode(null); - const dragEndEvent = this.nzTreeService.formatEvent('dragend', this.nzTreeNode, e); - this.nzDragEnd.emit(dragEndEvent); + const eventNext = this.nzTreeService.formatEvent('dragend', this.nzTreeNode, e); + this.nzTreeService.triggerEventChange$.next(eventNext); } }); } @@ -458,7 +417,7 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { } constructor( - private nzTreeService: NzTreeBaseService, + public nzTreeService: NzTreeBaseService, private ngZone: NgZone, private renderer: Renderer2, private elRef: ElementRef, @@ -467,13 +426,26 @@ export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy { } ngOnInit(): void { - this.setClassMap(); + // init expanded / selected / checked list + if (this.nzTreeNode.isSelected) { + this.nzTreeService.setNodeActive(this.nzTreeNode); + } + if (this.nzTreeNode.isExpanded) { + this.nzTreeService.setExpandedNodeList(this.nzTreeNode); + } + if (this.nzTreeNode.isChecked) { + this.nzTreeService.setCheckedNodeList(this.nzTreeNode); + } // TODO - this.nzTreeNode.setComponent(this); - this.nzTreeService.statusChanged().pipe(takeUntil(this.destroy$)).subscribe(() => { + this.nzTreeNode.component = this; + this.nzTreeService.eventTriggerChanged().pipe( + filter(data => data.node.key === this.nzTreeNode.key), + takeUntil(this.destroy$) + ).subscribe(() => { this.setClassMap(); this.markForCheck(); }); + this.setClassMap(); } ngOnChanges(): void { diff --git a/components/tree/nz-tree-node.ts b/components/tree/nz-tree-node.ts index dcdb8467cb..bde558dbf7 100644 --- a/components/tree/nz-tree-node.ts +++ b/components/tree/nz-tree-node.ts @@ -19,32 +19,32 @@ export interface NzTreeNodeOptions { } export class NzTreeNode { - title?: string; + private _title: string; key: string; + private _icon: string; level: number = 0; - children: NzTreeNode[]; - isLeaf: boolean; + private _children: NzTreeNode[]; + private _isLeaf: boolean; // tslint:disable-next-line:no-any origin: any; // Parent Node parentNode: NzTreeNode; - isChecked: boolean; - isSelectable: boolean; - isDisabled: boolean; - isDisableCheckbox: boolean; - isExpanded: boolean; - isHalfChecked: boolean; - isAllChecked: boolean; - isSelected: boolean; - isLoading: boolean; + private _isChecked: boolean; + private _isSelectable: boolean; + private _isDisabled: boolean; + private _isDisableCheckbox: boolean; + private _isExpanded: boolean; + private _isHalfChecked: boolean; + private _isSelected: boolean; + private _isLoading: boolean; isMatched: boolean; - private readonly service: NzTreeBaseService; - private component: NzTreeNodeComponent; + private _service: NzTreeBaseService; + component: NzTreeNodeComponent; get treeService(): NzTreeBaseService { - if (this.service) { - return this.service; + if (this._service) { + return this._service; } else if (this.parentNode) { return this.parentNode.treeService; } @@ -54,23 +54,23 @@ export class NzTreeNode { if (option instanceof NzTreeNode) { return option; } - this.service = service; - this.title = option.title || '---'; + this._service = service; + this._title = option.title || '---'; this.key = option.key || null; - this.isLeaf = option.isLeaf || false; + this._icon = option.icon || ''; + this._isLeaf = option.isLeaf || false; this.origin = option; - this.children = []; + 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.isLeaf ? false : (option.expanded || false); - this.isAllChecked = option.checked || false; - this.isHalfChecked = false; - this.isSelected = (!option.disabled && option.selected) || false; - this.isLoading = false; + 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.isLeaf ? false : (option.expanded || false); + this._isHalfChecked = false; + this._isSelected = (!option.disabled && option.selected) || false; + this._isLoading = false; this.isMatched = false; /** @@ -87,59 +87,146 @@ export class NzTreeNode { if ((this.treeService && !this.treeService.isCheckStrictly) && option.checked && !option.disabled && !nodeOptions.disabled && !nodeOptions.disableCheckbox) { nodeOptions.checked = option.checked; } - this.children.push(new NzTreeNode(nodeOptions, this)); + this._children.push(new NzTreeNode(nodeOptions, this)); } ); } } - public setComponent(component: NzTreeNodeComponent): void { - this.component = component; + /** + * auto generate + * get + * set + */ + get service(): NzTreeBaseService { + return this._service; } - public setSyncChecked(checked: boolean = false, halfChecked: boolean = false): void { - this.setChecked(checked, halfChecked); - if (!this.treeService.isCheckStrictly) { - this.treeService.conduct(this); - } + set service(value: NzTreeBaseService) { + this._service = value; } - public setChecked(checked: boolean = false, halfChecked: boolean = false): void { - this.origin.checked = checked; - this.isChecked = checked; - this.isAllChecked = checked; - this.isHalfChecked = halfChecked; - if (this.treeService) { - this.treeService.setCheckedNodeList(this); - this.treeService.setHalfCheckedNodeList(this); - this.treeService.$statusChange.next({ - 'eventName': 'setChecked', - 'node' : this - }); - } + get title(): string { + return this._title; + } + + set title(value: string) { + this._title = value; + this.update(); + } + + get icon(): string { + return this._icon; + } + + set icon(value: string) { + this._icon = value; + this.update(); + } + + get children(): NzTreeNode[] { + return this._children; + } + + set children(value: NzTreeNode[]) { + this._children = value; + this.update(); + } + + get isLeaf(): boolean { + return this._isLeaf; + } + + set isLeaf(value: boolean) { + this._isLeaf = value; + this.update(); + } + + get isChecked(): boolean { + return this._isChecked; + } + + set isChecked(value: boolean) { + this._isChecked = value; + this.origin.checked = value; + this.treeService.setCheckedNodeList(this); + this.update(); + } + + get isHalfChecked(): boolean { + return this._isHalfChecked; + } + + set isHalfChecked(value: boolean) { + this._isHalfChecked = value; + this.treeService.setHalfCheckedNodeList(this); + this.update(); + } + + get isSelectable(): boolean { + return this._isSelectable; + } + + set isSelectable(value: boolean) { + this._isSelectable = value; + this.update(); + } + + get isDisabled(): boolean { + return this._isDisabled; + } + + set isDisabled(value: boolean) { + this._isDisabled = value; + this.update(); + } + + get isDisableCheckbox(): boolean { + return this._isDisableCheckbox; + } + + set isDisableCheckbox(value: boolean) { + this._isDisableCheckbox = value; + this.update(); + } + + get isExpanded(): boolean { + return this._isExpanded; } - public setExpanded(value: boolean): void { + set isExpanded(value: boolean) { + this._isExpanded = value; this.origin.expanded = value; - this.isExpanded = value; this.treeService.setExpandedNodeList(this); - if (this.component) { - this.component.markForCheck(); - } + this.update(); } - public setSelected(value: boolean, isMultiple: boolean = this.treeService.isMultiple): void { - if (this.isDisabled) { - return; - } + get isSelected(): boolean { + return this._isSelected; + } + + set isSelected(value: boolean) { + this._isSelected = value; this.origin.selected = value; - this.isSelected = value; - this.treeService.setNodeActive(this, isMultiple); - if (this.component) { - this.component.markForCheck(); - } + this.treeService.setNodeActive(this); + this.update(); + } + + get isLoading(): boolean { + return this._isLoading; + } + + set isLoading(value: boolean) { + this._isLoading = value; + this.update(); } + /** + * end + * get + * set + */ + public getParentNode(): NzTreeNode { return this.parentNode; } @@ -182,7 +269,7 @@ export class NzTreeNode { this.origin.children = this.getChildren().map(v => v.origin); // remove loading state this.isLoading = false; - this.treeService.$statusChange.next({ + this.treeService.triggerEventChange$.next({ 'eventName': 'addChildren', 'node' : this }); @@ -197,9 +284,7 @@ export class NzTreeNode { this.origin.children = []; // refresh checked state this.treeService.calcCheckedKeys(this.treeService.checkedNodeList.map(v => v.key), this.treeService.rootNodes, this.treeService.isCheckStrictly); - if (this.component) { - this.component.markForCheck(); - } + this.update(); } public remove(): void { @@ -208,9 +293,14 @@ export class NzTreeNode { this.getParentNode().getChildren().splice(index, 1); this.getParentNode().origin.children.splice(index, 1); this.treeService.afterRemove(this); - if (this.component) { - this.component.markForCheck(); - } + this.update(); + } + } + + public update(): void { + if (this.component) { + this.component.setClassMap(); + this.component.markForCheck(); } } } diff --git a/components/tree/nz-tree.component.html b/components/tree/nz-tree.component.html index 1dedde83d8..e3ed665d66 100644 --- a/components/tree/nz-tree.component.html +++ b/components/tree/nz-tree.component.html @@ -2,7 +2,7 @@ role="tree" unselectable="on" [ngClass]="classMap"> - + + [nzNoAnimation]="noAnimation?.nzNoAnimation"> \ No newline at end of file diff --git a/components/tree/nz-tree.component.ts b/components/tree/nz-tree.component.ts index 6383d2114c..4c1d91d7f8 100644 --- a/components/tree/nz-tree.component.ts +++ b/components/tree/nz-tree.component.ts @@ -17,7 +17,8 @@ import { TemplateRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { Observable, ReplaySubject, Subscription } from 'rxjs'; +import { Observable, ReplaySubject, Subject, Subscription } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; import { NzNoAnimationDirective } from '../core/no-animation/nz-no-animation.directive'; import { isNotNil } from '../core/util/check'; import { InputBoolean } from '../core/util/convert'; @@ -65,17 +66,26 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal @Input() @InputBoolean() nzShowExpand = true; @Input() @InputBoolean() nzAsyncData = false; @Input() @InputBoolean() nzDraggable = false; - @Input() @InputBoolean() nzMultiple = false; - @Input() @InputBoolean() nzExpandAll: boolean = false; + @Input() @InputBoolean() nzExpandAll = false; @Input() @InputBoolean() nzHideUnMatched = false; @Input() @InputBoolean() nzSelectMode = false; /** * @deprecated use * nzExpandAll instead */ - @Input() @InputBoolean() nzDefaultExpandAll: boolean = false; + @Input() @InputBoolean() nzDefaultExpandAll = false; @Input() nzBeforeDrop: (confirm: NzFormatBeforeDropEvent) => Observable; + @Input() @InputBoolean() + set nzMultiple(value: boolean) { + this._nzMultiple = value; + this.nzTreeService.isMultiple = value; + } + + get nzMultiple(): boolean { + return this._nzMultiple; + } + @Input() // tslint:disable-next-line:no-any set nzData(value: any[]) { @@ -84,12 +94,14 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal // has not been new NzTreeNode this.nzNodes = value.map(item => (new NzTreeNode(item, null, this.nzTreeService))); } else { - this.nzNodes = value.map(item => (new NzTreeNode({ ...item.origin }, null, this.nzTreeService))); + this.nzNodes = value.map((item: NzTreeNode) => { + item.service = this.nzTreeService; + return item; + }); } this.nzTreeService.isCheckStrictly = this.nzCheckStrictly; this.nzTreeService.isMultiple = this.nzMultiple; this.nzTreeService.initTree(this.nzNodes); - this.cdr.markForCheck(); } else { if (value !== null) { console.warn('ngModel only accepts an array and must be not empty'); @@ -180,8 +192,10 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal // tslint:disable-next-line:no-any @ContentChild('nzTreeTemplate') nzTreeTemplate: TemplateRef; _searchValue = null; + _nzMultiple: boolean = false; nzDefaultSubject = new ReplaySubject<{ type: string, keys: string[] }>(6); nzDefaultSubscription: Subscription; + destroy$ = new Subject(); nzNodes: NzTreeNode[] = []; prefixCls = 'ant-tree'; classMap = {}; @@ -189,12 +203,8 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal onChange: (value: NzTreeNode[]) => void = () => null; onTouched: () => void = () => null; - trackByFn = (_index: number, item: NzTreeNode) => { - return item.key; - } - getTreeNodes(): NzTreeNode[] { - return this.nzNodes; + return this.nzTreeService.rootNodes; } getTreeNodeByKey(key: string): NzTreeNode { @@ -252,7 +262,10 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal writeValue(value: NzTreeNode[]): void { if (Array.isArray(value)) { - this.nzNodes = value.map(item => (new NzTreeNode({ ...item.origin }, null, this.nzTreeService))); + this.nzNodes = value.map((item: NzTreeNode) => { + item.service = this.nzTreeService; + return item; + }); this.nzTreeService.isCheckStrictly = this.nzCheckStrictly; this.nzTreeService.isMultiple = this.nzMultiple; this.nzTreeService.initTree(this.nzNodes); @@ -300,6 +313,46 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal } this.cdr.markForCheck(); }); + this.nzTreeService.eventTriggerChanged().pipe( + takeUntil(this.destroy$) + ).subscribe(data => { + switch (data.eventName) { + case 'expand': + this.nzExpandChange.emit(data); + break; + case 'click': + this.nzClick.emit(data); + break; + case 'check': + this.nzCheckBoxChange.emit(data); + break; + case 'dblclick': + this.nzDblClick.emit(data); + break; + case 'contextmenu': + this.nzContextMenu.emit(data); + break; + // drag drop + case 'dragstart': + this.nzOnDragStart.emit(data); + break; + case 'dragenter': + this.nzOnDragEnter.emit(data); + break; + case 'dragover': + this.nzOnDragOver.emit(data); + break; + case 'dragleave': + this.nzOnDragLeave.emit(data); + break; + case 'drop': + this.nzOnDrop.emit(data); + break; + case 'dragend': + this.nzOnDragEnd.emit(data); + break; + } + }); } ngOnChanges(changes: { [ propertyName: string ]: SimpleChange }): void { @@ -312,6 +365,9 @@ export class NzTreeComponent implements OnInit, OnChanges, OnDestroy, ControlVal } ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + this.destroy$ = null; if (this.nzDefaultSubscription) { this.nzDefaultSubscription.unsubscribe(); this.nzDefaultSubscription = null; diff --git a/components/tree/nz-tree.spec.ts b/components/tree/nz-tree.spec.ts index 22db6eaed5..981873b5f1 100644 --- a/components/tree/nz-tree.spec.ts +++ b/components/tree/nz-tree.spec.ts @@ -72,9 +72,6 @@ describe('nz-tree', () => { }); it('test new NzTreeNode of nzData', fakeAsync(() => { - fixture.detectChanges(); - flush(); - fixture.detectChanges(); treeInstance.nodes = [ { title : '0-0', key : '0-0', @@ -115,8 +112,7 @@ describe('nz-tree', () => { return (new NzTreeNode(v, null, treeService)); }); fixture.detectChanges(); - flush(); - tick(1000); + tick(100); fixture.detectChanges(); // reset node will clear default value except checked nodes list expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(1); @@ -272,7 +268,6 @@ describe('nz-tree', () => { 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); @@ -332,6 +327,17 @@ describe('nz-tree', () => { expect(treeElement.querySelectorAll('.ant-tree-switcher_open').length).toEqual(2); expect(fixture.componentInstance.treeComponent.getExpandedNodeList().length).toEqual(2); })); + + it('test set nzTreeNode', fakeAsync(() => { + // get 0-0 node + const node = fixture.componentInstance.treeComponent.getTreeNodeByKey('0-0'); + node.title = '0-0-reset'; + fixture.detectChanges(); + expect(treeElement.querySelectorAll('[title=\'0-0-reset\']').length).toEqual(1); + node.isDisabled = true; + fixture.detectChanges(); + expect(treeElement.querySelector('.ant-tree-treenode-disabled').querySelectorAll('[title=\'0-0-reset\']').length).toEqual(1); + })); }); describe('test draggable node', () => { @@ -423,28 +429,29 @@ describe('nz-tree', () => { // can not dispatchTouchEvent with pos, test alone it('test drag drop with dragPos', () => { // init selected node - treeService = treeInstance.treeComponent.nzTreeService.rootNodes[ 0 ].treeService; + const treeNodes = treeInstance.treeComponent.getTreeNodes(); 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 + let targetNode = treeNodes[ 0 ]; // 0-0 + treeService = treeNodes[ 1 ].treeService; treeService.dropAndApply(targetNode, -1); - expect(treeService.rootNodes[ 0 ].title).toEqual('0-0-0'); - expect(treeService.rootNodes[ 0 ].level).toEqual(0); + expect(treeNodes[ 0 ].title).toEqual('0-0-0'); + expect(treeNodes[ 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.selectedNode = treeNodes[ 0 ]; + targetNode = treeNodes[ 1 ].getChildren()[ 0 ]; // 0-0-1 treeService.dropAndApply(targetNode, 1); - expect(treeService.rootNodes[ 0 ].getChildren()[ 1 ].title).toEqual('0-0-0'); - expect(treeService.rootNodes[ 0 ].getChildren()[ 1 ].level).toEqual(1); + expect(treeNodes[ 0 ].getChildren()[ 1 ].title).toEqual('0-0-0'); + expect(treeNodes[ 0 ].getChildren()[ 1 ].level).toEqual(1); // 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.selectedNode = treeNodes[ 0 ].getChildren()[ 0 ]; + targetNode = treeNodes[ 0 ].getChildren()[ 1 ]; // 0-0-1 treeService.dropAndApply(targetNode, 1); - expect(treeService.rootNodes[ 0 ].getChildren()[ 0 ].title).toEqual('0-0-0'); + expect(treeNodes[ 0 ].getChildren()[ 0 ].title).toEqual('0-0-0'); }); it('test wrong drag event', fakeAsync(() => { @@ -545,22 +552,32 @@ describe('nz-tree', () => { }); }); - it('test node function', () => { + it('test node function', fakeAsync(() => { fixture.detectChanges(); fixture.componentInstance.checkedKeys = [ ...fixture.componentInstance.checkedKeys ]; fixture.componentInstance.expandKeys = [ ...fixture.componentInstance.expandKeys ]; fixture.componentInstance.selectedKeys = [ ...fixture.componentInstance.selectedKeys ]; fixture.detectChanges(); // get node by key - expect(fixture.componentInstance.treeComponent.getTreeNodeByKey('10001').title).toEqual('child1'); + let node = fixture.componentInstance.treeComponent.getTreeNodeByKey('10001'); + expect(node.title).toEqual('child1'); // test clear children - const node = fixture.componentInstance.treeComponent.getTreeNodes()[ 0 ].getChildren()[ 0 ]; // child1 10001 node.clearChildren(); expect(node.getChildren().length).toEqual(0); // remove self node.remove(); expect(node.getParentNode().getChildren().findIndex(v => v.key === node.key)).toEqual(-1); - }); + // test selectable false and click it + node = fixture.componentInstance.treeComponent.getTreeNodeByKey('1001'); + node.isSelectable = false; + fixture.detectChanges(); + // add nzTreeNode children to clear loading state, root click will not change + const targetNode = treeElement.querySelectorAll('li')[ 0 ]; + expect(targetNode.querySelectorAll('.ant-tree-treenode-selected').length).toEqual(0); + dispatchMouseEvent(targetNode, 'click'); + fixture.detectChanges(); + expect(targetNode.querySelectorAll('.ant-tree-treenode-selected').length).toEqual(0); + })); }); });