diff --git a/components/tree/demo/basic.ts b/components/tree/demo/basic.ts
index e9be2a7c740..754d6ca007a 100644
--- a/components/tree/demo/basic.ts
+++ b/components/tree/demo/basic.ts
@@ -13,6 +13,7 @@ import { NzFormatEmitEvent, NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd'
[nzExpandedKeys]="defaultExpandedKeys"
[nzSelectedKeys]="defaultSelectedKeys"
(nzClick)="nzClick($event)"
+ (nzSelectedKeysChange)="nzSelect($event)"
(nzCheckBoxChange)="nzCheck($event)">
`
@@ -45,17 +46,21 @@ export class NzDemoTreeBasicComponent implements OnInit {
} ];
nzClick(event: NzFormatEmitEvent): void {
- console.log(event, event.selectedKeys, event.keys, event.nodes);
+ console.log(event, event.selectedKeys, event.keys, event.nodes, this.treeCom.getSelectedNodeList());
}
nzCheck(event: NzFormatEmitEvent): void {
console.log(event, event.checkedKeys, event.keys, event.nodes);
}
+ // nzSelectedKeys change
+ nzSelect(keys: string[]): void {
+ console.log(keys, this.treeCom.getSelectedNodeList());
+ }
+
ngOnInit(): void {
setTimeout(() => {
- console.log(this.treeCom.getTreeNodes(), this.treeCom.getCheckedNodeList());
+ console.log(this.treeCom.getTreeNodes(), this.treeCom.getCheckedNodeList(), this.treeCom.getSelectedNodeList());
}, 500);
-
}
}
diff --git a/components/tree/nz-tree-node.component.html b/components/tree/nz-tree-node.component.html
index 29bff3ca43f..ca4ecf77fd8 100644
--- a/components/tree/nz-tree-node.component.html
+++ b/components/tree/nz-tree-node.component.html
@@ -1,6 +1,7 @@
-
-
-
-
+
+
+
+
+
+
+
+
@@ -48,7 +53,7 @@
[ngClass]="nzNodeContentLoadingClass">
-
+
@@ -85,6 +90,7 @@
[nzExpandAll]="nzExpandAll"
[nzDefaultExpandAll]="nzDefaultExpandAll"
[nzSearchValue]="nzSearchValue"
+ [nzHideUnMatched]="nzHideUnMatched"
[nzBeforeDrop]="nzBeforeDrop"
[nzCheckStrictly]="nzCheckStrictly"
[nzTreeTemplate]="nzTreeTemplate"
diff --git a/components/tree/nz-tree-node.component.ts b/components/tree/nz-tree-node.component.ts
index 4796e1ca854..fc22606ff07 100644
--- a/components/tree/nz-tree-node.component.ts
+++ b/components/tree/nz-tree-node.component.ts
@@ -1,13 +1,22 @@
import { animate, state, style, transition, trigger } from '@angular/animations';
import {
- Component, ElementRef, EventEmitter, HostListener,
- Input, NgZone,
+ Component,
+ ElementRef,
+ EventEmitter,
+ HostListener,
+ Input,
+ NgZone,
OnChanges,
- OnInit, Output, Renderer2,
- SimpleChanges,
- TemplateRef, ViewChild
+ OnDestroy,
+ OnInit,
+ Output,
+ Renderer2,
+ SimpleChange,
+ TemplateRef,
+ ViewChild
} from '@angular/core';
-import { fromEvent, Observable } from 'rxjs';
+import { fromEvent, Observable, Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
import { InputBoolean } from '../core/util/convert';
import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from '../tree/interface';
import { NzTreeNode } from './nz-tree-node';
@@ -35,16 +44,16 @@ import { NzTreeService } from './nz-tree.service';
]
})
-export class NzTreeNodeComponent implements OnInit, OnChanges {
+export class NzTreeNodeComponent implements OnInit, OnChanges, OnDestroy {
@ViewChild('dragElement') dragElement: ElementRef;
@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() @InputBoolean() nzHideUnMatched = false;
@Input() nzTreeTemplate: TemplateRef;
@Input() nzBeforeDrop: (confirm: NzFormatBeforeDropEvent) => Observable;
@@ -68,6 +77,16 @@ export class NzTreeNodeComponent implements OnInit, OnChanges {
return this._nzTreeNode;
}
+ @Input()
+ set nzDraggable(value: boolean) {
+ this._nzDraggable = value;
+ this.handDragEvent();
+ }
+
+ get nzDraggable(): boolean {
+ return this._nzDraggable;
+ }
+
/**
* @deprecated use
* nzExpandAll instead
@@ -103,14 +122,10 @@ export class NzTreeNodeComponent implements OnInit, OnChanges {
set nzSearchValue(value: string) {
this.highlightKeys = [];
if (value && this.nzTreeNode.title.includes(value)) {
- this.nzTreeNode.isMatched = true;
// 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));
- } else {
- // close the node if title does't contain search value
- this.nzTreeNode.isMatched = false;
}
this._searchValue = value;
}
@@ -145,6 +160,7 @@ export class NzTreeNodeComponent implements OnInit, OnChanges {
/**
* drag var
*/
+ destory$ = new Subject();
dragPos = 2;
dragPosClass: object = {
'0' : 'drag-over',
@@ -158,11 +174,28 @@ export class NzTreeNodeComponent implements OnInit, OnChanges {
_nzTreeNode: NzTreeNode;
_searchValue = '';
_nzExpandAll = false;
+ _nzDraggable = false;
+ oldAPIIcon = true;
+
+ 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;
+ }
get canDraggable(): boolean | null {
return (this.nzDraggable && this.nzTreeNode && !this.nzTreeNode.isDisabled) ? true : null;
}
+ get isShowLineIcon(): boolean {
+ return !this.nzTreeNode.isLeaf && this.nzShowLine;
+ }
+
+ get isShowSwitchIcon(): boolean {
+ return !this.nzTreeNode.isLeaf && !this.nzShowLine;
+ }
+
get isSwitcherOpen(): boolean {
return (this.nzTreeNode.isExpanded && !this.nzTreeNode.isLeaf);
}
@@ -171,6 +204,11 @@ export class NzTreeNodeComponent implements OnInit, OnChanges {
return (!this.nzTreeNode.isExpanded && !this.nzTreeNode.isLeaf);
}
+ get displayStyle(): string {
+ // TODO
+ return (this.nzSearchValue && this.nzHideUnMatched && !this.nzTreeNode.isMatched && !this.nzTreeNode.isExpanded) ? 'none' : '';
+ }
+
/**
* reset node class
*/
@@ -367,22 +405,39 @@ export class NzTreeNodeComponent implements OnInit, OnChanges {
});
}
- 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));
+ /**
+ * 监听拖拽事件
+ */
+ handDragEvent(): void {
+ this.ngZone.runOutsideAngular(() => {
+ if (this.nzDraggable) {
+ this.destory$ = new Subject();
+ fromEvent(this.elRef.nativeElement, 'dragstart').pipe(takeUntil(this.destory$)).subscribe((e: DragEvent) => this.handleDragStart(e));
+ fromEvent(this.elRef.nativeElement, 'dragenter').pipe(takeUntil(this.destory$)).subscribe((e: DragEvent) => this.handleDragEnter(e));
+ fromEvent(this.elRef.nativeElement, 'dragover').pipe(takeUntil(this.destory$)).subscribe((e: DragEvent) => this.handleDragOver(e));
+ fromEvent(this.elRef.nativeElement, 'dragleave').pipe(takeUntil(this.destory$)).subscribe((e: DragEvent) => this.handleDragLeave(e));
+ fromEvent(this.elRef.nativeElement, 'drop').pipe(takeUntil(this.destory$)).subscribe((e: DragEvent) => this.handleDragDrop(e));
+ fromEvent(this.elRef.nativeElement, 'dragend').pipe(takeUntil(this.destory$)).subscribe((e: DragEvent) => this.handleDragEnd(e));
+ } else {
+ this.destory$.next();
+ this.destory$.complete();
+ }
});
}
+ constructor(private nzTreeService: NzTreeService, private ngZone: NgZone, private renderer: Renderer2, private elRef: ElementRef) {
+ }
+
ngOnInit(): void {
this.setClassMap();
}
- ngOnChanges(changes: SimpleChanges): void {
+ ngOnChanges(changes: { [ propertyName: string ]: SimpleChange }): void {
this.setClassMap();
}
+
+ ngOnDestroy(): void {
+ this.destory$.next();
+ this.destory$.complete();
+ }
}
diff --git a/components/tree/nz-tree.component.html b/components/tree/nz-tree.component.html
index b16cf9e4ac7..61eb904b3e5 100644
--- a/components/tree/nz-tree.component.html
+++ b/components/tree/nz-tree.component.html
@@ -12,6 +12,7 @@
[nzAsyncData]="nzAsyncData"
[nzMultiple]="nzMultiple"
[nzSearchValue]="nzSearchValue"
+ [nzHideUnMatched]="nzHideUnMatched"
[nzBeforeDrop]="nzBeforeDrop"
[nzCheckStrictly]="nzCheckStrictly"
[nzExpandAll]="nzExpandAll"
diff --git a/components/tree/nz-tree.component.ts b/components/tree/nz-tree.component.ts
index a53465f4dcd..87b40e79b47 100644
--- a/components/tree/nz-tree.component.ts
+++ b/components/tree/nz-tree.component.ts
@@ -4,11 +4,15 @@ import {
ContentChild,
EventEmitter,
Input,
+ OnChanges,
OnDestroy,
- OnInit, Output, TemplateRef
+ OnInit,
+ Output,
+ SimpleChange,
+ TemplateRef
} from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
-import { Observable, Subject, Subscription } from 'rxjs';
+import { Observable, ReplaySubject, Subscription } from 'rxjs';
import { isNotNil } from '../core/util/check';
import { InputBoolean } from '../core/util/convert';
import { NzFormatBeforeDropEvent, NzFormatEmitEvent } from '../tree/interface';
@@ -28,7 +32,7 @@ import { NzTreeService } from './nz-tree.service';
]
})
-export class NzTreeComponent implements OnInit, OnDestroy {
+export class NzTreeComponent implements OnInit, OnChanges, OnDestroy {
@Input() @InputBoolean() nzShowIcon = false;
@Input() @InputBoolean() nzShowLine = false;
@Input() @InputBoolean() nzCheckStrictly = false;
@@ -38,6 +42,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
@Input() @InputBoolean() nzDraggable = false;
@Input() @InputBoolean() nzMultiple = false;
@Input() @InputBoolean() nzExpandAll: boolean = false;
+ @Input() @InputBoolean() nzHideUnMatched = false;
/**
* @deprecated use
* nzExpandAll instead
@@ -48,7 +53,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
@Input()
// tslint:disable-next-line:no-any
set nzData(value: any[]) {
- if (Array.isArray(value) && value.length > 0) {
+ if (Array.isArray(value)) {
if (!this.nzTreeService.isArrayOfNzTreeNode(value)) {
// has not been new NzTreeNode
this.nzNodes = value.map(item => (new NzTreeNode(item)));
@@ -59,7 +64,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
this.nzTreeService.initTree(this.nzNodes);
} else {
if (value !== null) {
- console.warn('ngModel only accepts an array and should be not empty');
+ console.warn('ngModel only accepts an array and must be not empty');
}
}
}
@@ -70,9 +75,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
*/
@Input()
set nzDefaultExpandedKeys(value: string[]) {
- setTimeout(() => {
- this.nzDefaultSubject.next({ type: 'nzExpandedKeys', keys: value });
- });
+ this.nzDefaultSubject.next({ type: 'nzExpandedKeys', keys: value });
}
/**
@@ -81,9 +84,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
*/
@Input()
set nzDefaultSelectedKeys(value: string[]) {
- setTimeout(() => {
- this.nzDefaultSubject.next({ type: 'nzSelectedKeys', keys: value });
- });
+ this.nzDefaultSubject.next({ type: 'nzSelectedKeys', keys: value });
}
/**
@@ -92,30 +93,22 @@ export class NzTreeComponent implements OnInit, OnDestroy {
*/
@Input()
set nzDefaultCheckedKeys(value: string[]) {
- setTimeout(() => {
- this.nzDefaultSubject.next({ type: 'nzCheckedKeys', keys: value });
- });
+ this.nzDefaultSubject.next({ type: 'nzCheckedKeys', keys: value });
}
@Input()
set nzExpandedKeys(value: string[]) {
- setTimeout(() => {
- this.nzDefaultSubject.next({ type: 'nzExpandedKeys', keys: value });
- });
+ this.nzDefaultSubject.next({ type: 'nzExpandedKeys', keys: value });
}
@Input()
set nzSelectedKeys(value: string[]) {
- setTimeout(() => {
- this.nzDefaultSubject.next({ type: 'nzSelectedKeys', keys: value });
- });
+ this.nzDefaultSubject.next({ type: 'nzSelectedKeys', keys: value });
}
@Input()
set nzCheckedKeys(value: string[]) {
- setTimeout(() => {
- this.nzDefaultSubject.next({ type: 'nzCheckedKeys', keys: value });
- });
+ this.nzDefaultSubject.next({ type: 'nzCheckedKeys', keys: value });
}
@Input()
@@ -159,9 +152,9 @@ export class NzTreeComponent implements OnInit, OnDestroy {
// tslint:disable-next-line:no-any
@ContentChild('nzTreeTemplate') nzTreeTemplate: TemplateRef;
- _searchValue = '';
+ _searchValue = null;
// tslint:disable-next-line:no-any
- nzDefaultSubject = new Subject();
+ nzDefaultSubject = new ReplaySubject(6);
nzDefaultSubscription: Subscription;
nzNodes: NzTreeNode[] = [];
prefixCls = 'ant-tree';
@@ -207,7 +200,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
}
writeValue(value: NzTreeNode[]): void {
- if (Array.isArray(value) && value.length > 0) {
+ if (Array.isArray(value)) {
this.nzNodes = value;
this.nzTreeService.conductOption.isCheckStrictly = this.nzCheckStrictly;
this.nzTreeService.initTree(this.nzNodes);
@@ -232,7 +225,7 @@ export class NzTreeComponent implements OnInit, OnDestroy {
ngOnInit(): void {
this.setClassMap();
this.nzDefaultSubscription = this.nzDefaultSubject.subscribe((data: { type: string, keys: string[] }) => {
- if (data.keys.length === 0) {
+ if (!data || !data.keys) {
return;
}
switch (data.type) {
@@ -252,6 +245,12 @@ export class NzTreeComponent implements OnInit, OnDestroy {
});
}
+ ngOnChanges(changes: { [ propertyName: string ]: SimpleChange }): void {
+ if (changes.nzCheckStrictly) {
+ this.nzTreeService.conductOption.isCheckStrictly = changes.nzCheckStrictly.currentValue;
+ }
+ }
+
ngOnDestroy(): void {
if (this.nzDefaultSubscription) {
this.nzDefaultSubscription.unsubscribe();
diff --git a/components/tree/nz-tree.service.ts b/components/tree/nz-tree.service.ts
index c806bc4ae77..029795ffb3e 100644
--- a/components/tree/nz-tree.service.ts
+++ b/components/tree/nz-tree.service.ts
@@ -47,32 +47,32 @@ export class NzTreeService {
* get some list
*/
getSelectedNodeList(): NzTreeNode[] {
- return this.selectedNodeList;
+ return this.conductNodeState('select');
}
/**
* return checked nodes
*/
getCheckedNodeList(): NzTreeNode[] {
- return this.conductCheck('check');
+ return this.conductNodeState('check');
}
getHalfCheckedNodeList(): NzTreeNode[] {
- return this.conductCheck('halfCheck');
+ return this.conductNodeState('halfCheck');
}
/**
* return expanded nodes
*/
getExpandedNodeList(): NzTreeNode[] {
- return this.expandedNodeList;
+ return this.conductNodeState('expand');
}
/**
* return search matched nodes
*/
getMatchedNodeList(): NzTreeNode[] {
- return this.matchedNodeList;
+ return this.conductNodeState('match');
}
// tslint:disable-next-line:no-any
@@ -99,7 +99,6 @@ export class NzTreeService {
});
};
calc(nzNodes);
-
}
/**
@@ -216,15 +215,15 @@ export class NzTreeService {
}
/**
- * conduct checked keys
+ * conduct checked/selected/expanded keys
*/
- conductCheck(type: string = 'check'): NzTreeNode[] {
- const checkedNodeList = [];
+ conductNodeState(type: string = 'check'): NzTreeNode[] {
+ const resultNodesList = [];
const loop = (node: NzTreeNode) => {
switch (type) {
case 'check':
if (node.isChecked) {
- checkedNodeList.push(node);
+ resultNodesList.push(node);
}
if (!this.conductOption.isCheckStrictly) {
if (!node.isChecked) {
@@ -241,19 +240,43 @@ export class NzTreeService {
case 'halfCheck':
if (!this.conductOption.isCheckStrictly) {
if (node.isHalfChecked) {
- checkedNodeList.push(node);
+ resultNodesList.push(node);
node.getChildren().forEach(child => {
loop(child);
});
}
}
break;
+ case 'select':
+ if (node.isSelected) {
+ resultNodesList.push(node);
+ }
+ node.getChildren().forEach(child => {
+ loop(child);
+ });
+ break;
+ case 'expand':
+ if (node.isExpanded) {
+ resultNodesList.push(node);
+ }
+ node.getChildren().forEach(child => {
+ loop(child);
+ });
+ break;
+ case 'match':
+ if (node.isMatched) {
+ resultNodesList.push(node);
+ }
+ node.getChildren().forEach(child => {
+ loop(child);
+ });
+ break;
}
};
this.rootNodes.forEach(node => {
loop(node);
});
- return checkedNodeList;
+ return resultNodesList;
}
/**
@@ -350,10 +373,12 @@ export class NzTreeService {
const searchChild = (n: NzTreeNode) => {
if (value && n.title.includes(value)) {
// match the node
+ n.isMatched = true;
this.matchedNodeList.push(n);
// expand parentNode
expandParent(n);
} else {
+ n.isMatched = false;
n.setExpanded(false);
this.setExpandedNodeList(n);
}
@@ -475,19 +500,16 @@ export class NzTreeService {
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) });
diff --git a/components/tree/nz-tree.spec.ts b/components/tree/nz-tree.spec.ts
index dbb5deea30e..a9f1982ebfc 100644
--- a/components/tree/nz-tree.spec.ts
+++ b/components/tree/nz-tree.spec.ts
@@ -1,5 +1,5 @@
import { Component, ViewChild } from '@angular/core';
-import { async, fakeAsync, tick, TestBed } from '@angular/core/testing';
+import { async, fakeAsync, flush, 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';
@@ -66,6 +66,8 @@ describe('nz-tree', () => {
});
it('test new NzTreeNode of nzData', fakeAsync(() => {
+ fixture.detectChanges();
+ flush();
fixture.detectChanges();
treeInstance.nodes = [ {
title : '0-0',
@@ -523,8 +525,6 @@ describe('nz-tree', () => {
});
it('should get correctly nodes', fakeAsync(() => {
- fixture.detectChanges();
- tick(200);
fixture.detectChanges();
// unsupported type, will console `ngModel only accepts an array and should be not empty`
expect(treeInstance.treeComponent.getCheckedNodeList().length).toEqual(1);
@@ -535,8 +535,8 @@ describe('nz-tree', () => {
expect(treeInstance.treeComponent.getHalfCheckedNodeList()[ 0 ].key).toEqual('1001');
expect(treeInstance.treeComponent.getSelectedNodeList().length).toEqual(2);
// test clear children
- treeInstance.treeComponent.getTreeNodes()[0].clearChildren();
- expect(treeInstance.treeComponent.getTreeNodes()[0].getChildren().length).toEqual(0);
+ treeInstance.treeComponent.getTreeNodes()[ 0 ].clearChildren();
+ expect(treeInstance.treeComponent.getTreeNodes()[ 0 ].getChildren().length).toEqual(0);
}));