Mat-tree angular materialコンポーネントを使用しています。これは、複数選択、すべて展開/すべて折りたたむなど、非常に便利な機能を備えたNiceコンポーネントです。ツリーフィルタリングは見つかりませんでした。 APIのいずれかの機能:マットツリーフィルターを取得するために、この機能に遭遇した人や回避策を実行した人はいますか。
新しいデータソースを作成することで問題を解決しました(フィルター処理済み)。
共有リンクの例を説明します:ChecklistDatabase
のfilter(filterText: string)
でデータをフィルタリングし、dataChange
イベントをトリガーしました。その後、datasource.data
は、TreeChecklistExample
で処理されたイベントによって変更されました。したがって、データソースが変更されました。
filter(filterText: string) {
let filteredTreeData;
if (filterText) {
filteredTreeData = this.treeData.filter(
//There is filter function in the sample
);
} else {
filteredTreeData = this.treeData;
}
// file node as children.
const data = this.buildFileTree(filteredTreeData, '0');
// Notify the change. !!!IMPORTANT
this.dataChange.next(data);
}
同じタスクに数日間費やした後、ここで私が与えることができるいくつかのヒントがあります:入力イベントを使用してユーザー入力を追跡しています:
<input matInput class="form-control"
(input)="filterChanged($event.target.value)"
placeholder="Search Skill">
このフィルターにサブジェクトを添付して、サブスクライブできるようにしました。
searchFilter: Subject<string> = new Subject<string>();
filterChanged(filter: string): void {
this.searchFilter.next(filter);
}
ユーザーにとってスムーズにするために、通常、debounceTime
で実行できる検索の実行を遅らせたいと思います。
this.searchFilter.pipe(debounceTime(500), distinctUntilChanged())
.subscribe(value => {
if (value && value.length >= 3) {
this.filterByName(value);
} else {
this.clearFilter();
}
});
検索を実行するには、cssクラスを使用してノードを非表示および表示します。これはプレゼンテーションコレクションで直接行われ、フラットで非常に簡単にフィルター処理できます。
treeControl: FlatTreeControl<SkillFlatNode>;
this.treeControl.dataNodes
まず、すべてを非表示にしてから、基準に一致するもののみを表示します。最後に、彼らの両親を見せたいのですが、これは私のツリー構造に特有のものです。
private filterByName(term: string): void {
const filteredItems = this.treeControl.dataNodes.filter(
x => x.value.DisplayName.toLowerCase().indexOf(term.toLowerCase()) === -1
);
filteredItems.map(x => {
x.visible = false;
});
const visibleItems = this.treeControl.dataNodes.filter(
x => x.value.IsSkill &&
x.value.DisplayName.toLowerCase().indexOf(term.toLowerCase()) > -1
);
visibleItems.map( x => {
x.visible = true;
this.markParent(x);
});
}
最後に、明確なフィルターを示します。
private clearFilter(): void {
this.treeControl.dataNodes.forEach(x => x.visible = true);
}
私がやったように同じ間違いをしないで、入力コレクション(this.dataSource.data
私の場合)選択を失うか、プレゼンテーションにマップし直す必要があるため。ここに私の初期データがあります:
this.treeFlattener = new MatTreeFlattener(
this.transformer, this._getLevel, this._isExpandable, this._getChildren
);
this.treeControl = new FlatTreeControl<SkillFlatNode>(
this._getLevel, this._isExpandable
);
this.dataSource = new MatTreeFlatDataSource(
this.treeControl, this.treeFlattener
);
skillService.dataChange.subscribe(data => {
this.dataSource.data = data;
});
単純な再帰を使用してツリーをフィルター処理できます。以下にコードスニペットを示します。
filter()
関数は、(keyup)
のinput type="text"
で呼び出されます。 cloneDeep
関数はlodashからインポートされますimport * as cloneDeep from 'lodash/cloneDeep';
this.searchString
は、フィルターテキストの文字列値です。
filter() {
const clonedTreeLocal = cloneDeep(this.clonedTree);
this.recursiveNodeEliminator(clonedTreeLocal);
this.dataSource.data = clonedTreeLocal;
this.treeControl.expandAll();
}
ツリー構造はインターフェースによって定義されます
export interface ITreeDataStructure {
Id?: number;
name: string;
type: string;
children?: Array<ITreeDataStructure>;
}
実際のフィルタリングは、関数recursiveNodeEliminator
によって行われます
recursiveNodeEliminator(tree: Array<ITreeDataStructure>): boolean {
for (let index = tree.length - 1; index >= 0; index--) {
const node = tree[index];
if (node.children) {
const parentCanBeEliminated = this.recursiveNodeEliminator(node.children);
if (parentCanBeEliminated) {
if (node.name.toLocaleLowerCase().indexOf(this.searchString.toLocaleLowerCase()) === -1) {
tree.splice(index, 1);
}
}
} else {
// Its a leaf node. No more branches.
if (node.name.toLocaleLowerCase().indexOf(this.searchString.toLocaleLowerCase()) === -1) {
tree.splice(index, 1);
}
}
}
return tree.length === 0;
}
まず、ビューにフィルターとして入力を追加します。キーアップイベントをrxjsにバインドするSubject
<input type="text" matInput placeholder="search" #filter (keyup)="keyEvent.next($event)" [(ngModel)]="keyword">
次に、キーワードでツリーノードをフィルタリングするためにバックエンドをクエリします
this.keyEvent.pipe(
map((e: any) => e.target.value.toLowerCase()),
debounceTime(500),
distinctUntilChanged(),
switchMap((keyword: string) => {
if (keyword && keyword.length > 2) {
return this.yourservice.searchForData(this.entId, keyword);
} else {
return of();
}
})
)
.subscribe((r) => {
this.nestedDataSource.data = r;
this.nestedTreeControl.dataNodes = r;
this.nestedTreeControl.expandAll();
});