- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
目前我正在尝试使用 Angular Material 树组件为动态数据开发树结构,我遵循下面提到的代码示例:
https://stackblitz.com/edit/material-tree-dynamic
由于我开发的树不能正常工作,我原样复制了上面的代码并尝试在我的机器上运行。但折叠功能不起作用。这是我的 typescript 文件(html 完全一样):
import {Component, Injectable} from '@angular/core';
import {FlatTreeControl} from '@angular/cdk/tree';
import {CollectionViewer, SelectionChange} from '@angular/cdk/collections';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Observable} from 'rxjs/Observable';
import {merge} from 'rxjs/observable/merge';
import {map} from 'rxjs/operators/map';
/** Flat node with expandable and level information */
export class DynamicFlatNode {
constructor(public item: string, public level: number = 1, public expandable: boolean = false, public isLoading: boolean = false) {}
}
/**
* Database for dynamic data. When expanding a node in the tree, the data source will need to fetch
* the descendants data from the database.
*/
export class DynamicDatabase {
dataMap = new Map([
['Simulation', ['Factorio', 'Oxygen not included']],
['Indie', [`Don't Starve`, 'Terraria', 'Starbound', 'Dungeon of the Endless']],
['Action', ['Overcooked']],
['Strategy', ['Rise to ruins']],
['RPG', ['Magicka']],
['Magicka', ['Magicka 1', 'Magicka 2']],
[`Don't Starve`, ['Region of Giants', 'Together', 'Shipwrecked']]
]);
rootLevelNodes = ['Simulation', 'Indie', 'Action', 'Strategy', 'RPG'];
/** Initial data from database */
initialData(): DynamicFlatNode[] {
return this.rootLevelNodes.map(name => new DynamicFlatNode(name, 0, true));
}
getChildren(node: string): string[] | undefined {
return this.dataMap.get(node);
}
isExpandable(node: string): boolean {
return this.dataMap.has(node);
}
}
/**
* File database, it can build a tree structured Json object from string.
* Each node in Json object represents a file or a directory. For a file, it has filename and type.
* For a directory, it has filename and children (a list of files or directories).
* The input will be a json object string, and the output is a list of `FileNode` with nested
* structure.
*/
@Injectable()
export class DynamicDataSource {
dataChange: BehaviorSubject<DynamicFlatNode[]> = new BehaviorSubject<DynamicFlatNode[]>([]);
get data(): DynamicFlatNode[] { return this.dataChange.value; }
set data(value: DynamicFlatNode[]) {
this.treeControl.dataNodes = value;
this.dataChange.next(value);
}
constructor(private treeControl: FlatTreeControl<DynamicFlatNode>,
private database: DynamicDatabase) {}
connect(collectionViewer: CollectionViewer): Observable<DynamicFlatNode[]> {
this.treeControl.expansionModel.onChange!.subscribe(change => {
if ((change as SelectionChange<DynamicFlatNode>).added ||
(change as SelectionChange<DynamicFlatNode>).removed) {
this.handleTreeControl(change as SelectionChange<DynamicFlatNode>);
}
});
return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
}
/** Handle expand/collapse behaviors */
handleTreeControl(change: SelectionChange<DynamicFlatNode>) {
if (change.added) {
change.added.forEach((node) => this.toggleNode(node, true));
}
if (change.removed) {
change.removed.reverse().forEach((node) => this.toggleNode(node, false));
}
}
/**
* Toggle the node, remove from display list
*/
toggleNode(node: DynamicFlatNode, expand: boolean) {
const children = this.database.getChildren(node.item);
const index = this.data.indexOf(node);
if (!children || index < 0) { // If no children, or cannot find the node, no op
return;
}
if (expand) {
node.isLoading = true;
setTimeout(() => {
const nodes = children.map(name =>
new DynamicFlatNode(name, node.level + 1, this.database.isExpandable(name)));
this.data.splice(index + 1, 0, ...nodes);
// notify the change
this.dataChange.next(this.data);
node.isLoading = false;
}, 1000);
} else {
this.data.splice(index + 1, children.length);
this.dataChange.next(this.data);
}
}
}
@Component({
selector: 'app-audience-tree',
templateUrl: './audience-tree.component.html',
styleUrls: ['./audience-tree.component.css'],
providers: [DynamicDatabase]
})
export class AudienceTreeComponent{
constructor(database: DynamicDatabase) {
this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
this.dataSource = new DynamicDataSource(this.treeControl, database);
this.dataSource.data = database.initialData();
}
treeControl: FlatTreeControl<DynamicFlatNode>;
dataSource: DynamicDataSource;
getLevel = (node: DynamicFlatNode) => { return node.level; };
isExpandable = (node: DynamicFlatNode) => { return node.expandable; };
hasChild = (_: number, _nodeData: DynamicFlatNode) => { return _nodeData.expandable; };
}
当我折叠一个有超过 1 个子级的根节点时 this result will be given
伙计们,有人能告诉我这是什么原因吗?我该如何解决?这将是一个很大的帮助。
最佳答案
为什么会这样
原因是切换功能的实现方式。折叠节点时(调用 toggleNode
并为 expand 参数设置 false )执行以下行:
this.data.splice(index + 1, children.length);
在这种情况下, Material 树使用的 Flat Tree 数据结构将其所有元素存储在一个简单的数组中,以及每个节点的级别属性。因此一棵树可能看起来像这样:
- Root (lvl: 1)
- Child1 (lvl: 2)
- Child2 (lvl: 2)
- Child1OfChild2 (lvl: 3)
- Child2OfChild2 (lvl: 3)
- Child3 (lvl: 2)
请注意,展开节点时,子元素在数组中位于其父元素之后。当节点折叠时,节点的子元素应该从数组中移除。在这种情况下,只有当没有 child 被扩展并因此有 child 本身时,这才有效。如果我们再次查看我上面提到的代码行,就会清楚为什么会这样:
当折叠一个节点时,上面的代码行被调用。 splice
函数从第一个参数(index+1,也就是我们要获取的元素之后的第一个元素)传入的位置开始,移除一定数量的元素崩溃)。被移除的元素数量在第二个参数中传递(children.length,在本例中)。
在上面的示例中折叠 Child2 时,这将正常工作:元素从位置 index+1 删除(索引是 Child2 的位置)。由于 Child2 有两个 child ,children.length 将为两个,这意味着 splice
函数将恰好删除 Child1OfChild2 和 Child2OfChild2(如 index+1 是 Child1OfChild2 的位置)。
但是举例来说,我们想从上面的示例树中折叠根。在这种情况下,index+1 将是 Child1 的位置,这没问题。问题是 children.length 将返回 3,因为根只有三个直接子节点。这将导致从 Child1 开始删除数组的前三个元素,导致 Child2OfChild2 和 Child3 仍在数组中。
解决方案
我解决这个问题的方法是用以下逻辑替换有问题的代码行:
const afterCollapsed: ArtifactNode[] = this.data.slice(index + 1, this.data.length);
let count = 0;
for (count; count < afterCollapsed.length; count++) {
const tmpNode = afterCollapsed[count];
if (tmpNode.level <= node.level){
break;
}
}
this.data.splice(index+1, count);
在第一行中,我使用 slice
函数获取数组中我们折叠的节点之后的部分,直到数组末尾。在此之后,我使用 for 循环来计算此子数组的元素数量,这些元素的级别高于我们正在折叠的节点(更高级别意味着它们是子节点或孙子节点等)。一旦循环遇到与我们正在折叠的节点具有相同级别的节点,循环就会停止,我们将得到计数,其中包含我们要从节点后的第一个元素开始删除的元素数我们快崩溃了。使用 splice
函数删除元素发生在最后一行。
关于typescript - Angular 6 Material 树折叠功能无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53484824/
我在Windows 10中使用一些简单的Powershell代码遇到了这个奇怪的问题,我认为这可能是我做错了,但我不是Powershell的天才。 我有这个: $ix = [System.Net.Dn
var urlsearch = "http://192.168.10.113:8080/collective-intellegence/StoreClicks?userid=" + userId +
我有一个非常奇怪的问题,过去两天一直让我抓狂。 我有一个我试图控制的串行设备(LS 100 光度计)。使用设置了正确参数的终端(白蚁),我可以发送命令(“MES”),然后是定界符(CR LF),然后我
我目前正试图让无需注册的 COM 使用 Excel 作为客户端,使用 .NET dll 作为服务器。目前,我只是试图让概念验证工作,但遇到了麻烦。 显然,当我使用 Excel 时,我不能简单地使用与可
我开发了简单的 REST API - https://github.com/pavelpetrcz/MandaysFigu - 我的问题是在本地主机上,WildFly 16 服务器的应用程序运行正常。
我遇到了奇怪的情况 - 从 Django shell 创建一些 Mongoengine 对象是成功的,但是从 Django View 创建相同的对象看起来成功,但 MongoDB 中没有出现任何数据。
我是 flask 的新手,只编写了一个相当简单的网络应用程序——没有数据库,只是一个航类搜索 API 的前端。一切正常,但为了提高我的技能,我正在尝试使用应用程序工厂和蓝图重构我的代码。让它与 pus
我的谷歌分析 JavaScript 事件在开发者控制台中运行得很好。 但是当从外部 js 文件包含在页面上时,它们根本不起作用。由于某种原因。 例如; 下面的内容将在包含在控制台中时运行。但当包含在单
这是一本名为“Node.js 8 the Right Way”的书中的任务。你可以在下面看到它: 这是我的解决方案: 'use strict'; const zmq = require('zeromq
我正在阅读文本行,并创建其独特单词的列表(在将它们小写之后)。我可以使它与 flatMap 一起工作,但不能使它与 map 的“子”流一起工作。 flatMap 看起来更简洁和“更好”,但为什么 di
我正在编写一些 PowerShell 脚本来进行一些构建自动化。我发现 here echo $? 根据前面的语句返回真或假。我刚刚发现 echo 是 Write-Output 的别名。 写主机 $?
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 4年前关闭。 Improve thi
我将一个工作 View Controller 类从另一个项目复制到一个新项目中。我无法在新项目中加载 View 。在旧项目中我使用了presentModalViewController。在新版本中,我
我对 javascript 很陌生,所以很难看出我哪里出错了。由于某种原因,我的功能无法正常工作。任何帮助,将不胜感激。我尝试在外部 js 文件、头部/主体中使用它们,但似乎没有任何效果。错误要么出在
我正在尝试学习Flutter中的复选框。 问题是,当我想在Scaffold(body :)中使用复选框时,它正在工作。但我想在不同的地方使用它,例如ListView中的项目。 return Cente
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我有一个组合框,其中包含一个项目,比如“a”。我想调用该组合框的 Action 监听器,仅在手动选择项目“a”完成时才调用。我也尝试过 ItemStateChanged,但它的工作原理与 Action
你能看一下照片吗?现在,一步前我执行了 this.interrupt()。您可以看到 this.isInterrupted() 为 false。我仔细观察——“这个”没有改变。它具有相同的 ID (1
我们当前使用的是 sleuth 2.2.3.RELEASE,我们看不到在 http header 中传递的 userId 字段没有传播。下面是我们的代码。 BaggageField REQUEST_I
我正在尝试在我的网站上设置一个联系表单,当有人点击发送时,就会运行一个作业,并在该作业中向所有管理员用户发送通知。不过,我在失败的工作表中不断收到此错误: Illuminate\Database\El
我是一名优秀的程序员,十分优秀!