Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

WIP feat(module:tree-view): upgrade tree view #9003

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ interface FlatNode {
}

@Component({
selector: 'nz-demo-tree-view-basic',
selector: 'nz-demo-tree-view-legacy-basic',
imports: [NzIconModule, NzTreeViewModule],
template: `
<nz-tree-view [nzTreeControl]="treeControl" [nzDataSource]="dataSource">
Expand Down Expand Up @@ -66,7 +66,7 @@ interface FlatNode {
</nz-tree-view>
`
})
export class NzDemoTreeViewBasicComponent {
export class NzDemoTreeViewLegacyBasicComponent {
private transformer = (node: TreeNode, level: number): FlatNode => ({
expandable: !!node.children && node.children.length > 0,
name: node.name,
Expand Down
14 changes: 14 additions & 0 deletions components/tree-view-legacy/demo/checkbox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 1
title:
zh-CN: 选择框
en-US: checkbox
---

## zh-CN

带选择框的树。

## en-US

Tree with checkboxes.
181 changes: 181 additions & 0 deletions components/tree-view-legacy/demo/checkbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import { SelectionModel } from '@angular/cdk/collections';
import { FlatTreeControl } from '@angular/cdk/tree';
import { Component } from '@angular/core';

import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzTreeFlatDataSource, NzTreeFlattener, NzTreeViewModule } from 'ng-zorro-antd/tree-view';

interface TreeNode {
name: string;
disabled?: boolean;
children?: TreeNode[];
}

const TREE_DATA: TreeNode[] = [
{
name: '0-0',
disabled: true,
children: [{ name: '0-0-0' }, { name: '0-0-1' }, { name: '0-0-2' }]
},
{
name: '0-1',
children: [
{
name: '0-1-0',
children: [{ name: '0-1-0-0' }, { name: '0-1-0-1' }]
},
{
name: '0-1-1',
children: [{ name: '0-1-1-0' }, { name: '0-1-1-1' }]
}
]
}
];

interface FlatNode {
expandable: boolean;
name: string;
level: number;
disabled: boolean;
}

@Component({
selector: 'nz-demo-tree-view-legacy-checkbox',
imports: [NzIconModule, NzTreeViewModule],
template: `
<nz-tree-view [nzTreeControl]="treeControl" [nzDataSource]="dataSource">
<nz-tree-node *nzTreeNodeDef="let node" nzTreeNodePadding>
<nz-tree-node-toggle nzTreeNodeNoopToggle></nz-tree-node-toggle>
<nz-tree-node-checkbox
[nzDisabled]="node.disabled"
[nzChecked]="checklistSelection.isSelected(node)"
(nzClick)="leafItemSelectionToggle(node)"
></nz-tree-node-checkbox>
<nz-tree-node-option [nzDisabled]="node.disabled" (nzClick)="leafItemSelectionToggle(node)">
{{ node.name }}
</nz-tree-node-option>
</nz-tree-node>

<nz-tree-node *nzTreeNodeDef="let node; when: hasChild" nzTreeNodePadding>
<nz-tree-node-toggle>
<nz-icon nzType="caret-down" nzTreeNodeToggleRotateIcon />
</nz-tree-node-toggle>
<nz-tree-node-checkbox
[nzDisabled]="node.disabled"
[nzChecked]="descendantsAllSelected(node)"
[nzIndeterminate]="descendantsPartiallySelected(node)"
(nzClick)="itemSelectionToggle(node)"
></nz-tree-node-checkbox>
<nz-tree-node-option [nzDisabled]="node.disabled" (nzClick)="itemSelectionToggle(node)">
{{ node.name }}
</nz-tree-node-option>
</nz-tree-node>
</nz-tree-view>
`
})
export class NzDemoTreeViewLegacyCheckboxComponent {
private transformer = (node: TreeNode, level: number): FlatNode => {
const existingNode = this.nestedNodeMap.get(node);
const flatNode =
existingNode && existingNode.name === node.name
? existingNode
: {
expandable: !!node.children && node.children.length > 0,
name: node.name,
level,
disabled: !!node.disabled
};
this.flatNodeMap.set(flatNode, node);
this.nestedNodeMap.set(node, flatNode);
return flatNode;
};
flatNodeMap = new Map<FlatNode, TreeNode>();
nestedNodeMap = new Map<TreeNode, FlatNode>();
checklistSelection = new SelectionModel<FlatNode>(true);

treeControl = new FlatTreeControl<FlatNode>(
node => node.level,
node => node.expandable
);

treeFlattener = new NzTreeFlattener(
this.transformer,
node => node.level,
node => node.expandable,
node => node.children
);

dataSource = new NzTreeFlatDataSource(this.treeControl, this.treeFlattener);

constructor() {
this.dataSource.setData(TREE_DATA);
}

hasChild = (_: number, node: FlatNode): boolean => node.expandable;

descendantsAllSelected(node: FlatNode): boolean {
const descendants = this.treeControl.getDescendants(node);
return descendants.length > 0 && descendants.every(child => this.checklistSelection.isSelected(child));
}

descendantsPartiallySelected(node: FlatNode): boolean {
const descendants = this.treeControl.getDescendants(node);
const result = descendants.some(child => this.checklistSelection.isSelected(child));
return result && !this.descendantsAllSelected(node);
}

leafItemSelectionToggle(node: FlatNode): void {
this.checklistSelection.toggle(node);
this.checkAllParentsSelection(node);
}

itemSelectionToggle(node: FlatNode): void {
this.checklistSelection.toggle(node);
const descendants = this.treeControl.getDescendants(node);
this.checklistSelection.isSelected(node)
? this.checklistSelection.select(...descendants)
: this.checklistSelection.deselect(...descendants);

descendants.forEach(child => this.checklistSelection.isSelected(child));
this.checkAllParentsSelection(node);
}

checkAllParentsSelection(node: FlatNode): void {
let parent: FlatNode | null = this.getParentNode(node);
while (parent) {
this.checkRootNodeSelection(parent);
parent = this.getParentNode(parent);
}
}

checkRootNodeSelection(node: FlatNode): void {
const nodeSelected = this.checklistSelection.isSelected(node);
const descendants = this.treeControl.getDescendants(node);
const descAllSelected =
descendants.length > 0 && descendants.every(child => this.checklistSelection.isSelected(child));
if (nodeSelected && !descAllSelected) {
this.checklistSelection.deselect(node);
} else if (!nodeSelected && descAllSelected) {
this.checklistSelection.select(node);
}
}

getParentNode(node: FlatNode): FlatNode | null {
const currentLevel = node.level;

if (currentLevel < 1) {
return null;
}

const startIndex = this.treeControl.dataNodes.indexOf(node) - 1;

for (let i = startIndex; i >= 0; i--) {
const currentNode = this.treeControl.dataNodes[i];

if (currentNode.level < currentLevel) {
return currentNode;
}
}
return null;
}
}
14 changes: 14 additions & 0 deletions components/tree-view-legacy/demo/directory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 2
title:
zh-CN: 目录
en-US: Directory
---

## zh-CN

目录树

## en-US

Directory tree.
113 changes: 113 additions & 0 deletions components/tree-view-legacy/demo/directory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { SelectionModel } from '@angular/cdk/collections';
import { FlatTreeControl } from '@angular/cdk/tree';
import { AfterViewInit, Component } from '@angular/core';

import { NzIconModule } from 'ng-zorro-antd/icon';
import { NzTreeFlatDataSource, NzTreeFlattener, NzTreeViewModule } from 'ng-zorro-antd/tree-view';

interface FoodNode {
name: string;
disabled?: boolean;
children?: FoodNode[];
}

const TREE_DATA: FoodNode[] = [
{
name: 'Fruit',
children: [{ name: 'Apple' }, { name: 'Banana', disabled: true }, { name: 'Fruit loops' }]
},
{
name: 'Vegetables',
children: [
{
name: 'Green',
children: [{ name: 'Broccoli' }, { name: 'Brussels sprouts' }]
},
{
name: 'Orange',
children: [{ name: 'Pumpkins' }, { name: 'Carrots' }]
}
]
}
];

/** Flat node with expandable and level information */
interface ExampleFlatNode {
expandable: boolean;
name: string;
level: number;
disabled: boolean;
}

@Component({
selector: 'nz-demo-tree-view-legacy-directory',
imports: [NzIconModule, NzTreeViewModule],
template: `
<nz-tree-view [nzTreeControl]="treeControl" [nzDataSource]="dataSource" [nzDirectoryTree]="true">
<nz-tree-node *nzTreeNodeDef="let node" nzTreeNodePadding>
<nz-tree-node-toggle nzTreeNodeNoopToggle></nz-tree-node-toggle>
<nz-tree-node-option
[nzDisabled]="node.disabled"
[nzSelected]="selectListSelection.isSelected(node)"
(nzClick)="selectListSelection.toggle(node)"
>
<nz-icon nzType="file" nzTheme="outline" />
{{ node.name }}
</nz-tree-node-option>
</nz-tree-node>

<nz-tree-node *nzTreeNodeDef="let node; when: hasChild" nzTreeNodePadding>
<nz-tree-node-toggle>
<nz-icon nzType="caret-down" nzTreeNodeToggleRotateIcon />
</nz-tree-node-toggle>
<nz-tree-node-option
[nzDisabled]="node.disabled"
[nzSelected]="selectListSelection.isSelected(node)"
(nzClick)="selectListSelection.toggle(node)"
>
<nz-icon [nzType]="treeControl.isExpanded(node) ? 'folder-open' : 'folder'" nzTheme="outline" />
{{ node.name }}
</nz-tree-node-option>
</nz-tree-node>
</nz-tree-view>
`
})
export class NzDemoTreeViewLegacyDirectoryComponent implements AfterViewInit {
private transformer = (node: FoodNode, level: number): ExampleFlatNode => ({
expandable: !!node.children && node.children.length > 0,
name: node.name,
level,
disabled: !!node.disabled
});
selectListSelection = new SelectionModel<ExampleFlatNode>();

treeControl = new FlatTreeControl<ExampleFlatNode>(
node => node.level,
node => node.expandable
);

treeFlattener = new NzTreeFlattener(
this.transformer,
node => node.level,
node => node.expandable,
node => node.children
);

dataSource = new NzTreeFlatDataSource(this.treeControl, this.treeFlattener);

constructor() {
this.dataSource.setData(TREE_DATA);
}

hasChild = (_: number, node: ExampleFlatNode): boolean => node.expandable;

ngAfterViewInit(): void {
setTimeout(() => {
this.treeControl.expand(this.getNode('Vegetables')!);
}, 300);
}

getNode(name: string): ExampleFlatNode | null {
return this.treeControl.dataNodes.find(n => n.name === name) || null;
}
}
14 changes: 14 additions & 0 deletions components/tree-view-legacy/demo/dynamic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 3
title:
zh-CN: 异步加载数据
en-US: Load data asynchronously
---

## zh-CN

点击展开节点,动态加载数据。

## en-US

To load data asynchronously when click to expand a treeNode.
Loading
Loading