我已经寻找示例了一段时间,但是我找不到任何类似的东西,而且我对过滤器功能的了解不足,非常感谢任何帮助。我正在尝试从嵌套项目标签===未定义的对象中删除元素。
this.items = [ // main MenuItem[] object (contains entire menu)
{
label: this.headingLabel, visible: this.booleanPipe.transform(this.labelVisible),
items: [ // headings of the menu sit in navbar, a MenuItem[][] two dimensional array
[
{
label: this.subMenuLabel, visible: this.booleanPipe.transform(this.labelVisible), separator: true,
items: [ // items that need to be removed if they are undefined, another MenuItem[] object, potentially need to remove only some of its elements
{ label: this.subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: this.subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: undefined, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: this.subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: this.subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: undefined, visible: this.booleanPipe.transform(this.labelVisible) }
]
},
],
[
{
label: subMenuLabel, visible: this.booleanPipe.transform(this.labelVisible), separator: true,
items: [
{ label: subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) },
{ label: subMenuItemLabel, visible: this.booleanPipe.transform(this.labelVisible) }
]
}
]
]
},
...
我能够使用以下方法从未定义标签的主要对象中删除元素:
this.items = this.items.filter(obj => obj.label !== undefined);
但是我无法弄清楚如何嵌套另一个过滤器,映射或查找...不确定如何..以便能够访问嵌套项并检查其标签中的未定义项并将其删除!< / p>
EDIT1: this.items对象是一个MenuItem []数组。 MenuItem是PrimeNG类。它具有以下定义:
export interface MenuItem {
label?: string;
icon?: string;
command?: (event?: any) => void;
url?: string;
routerLink?: any;
queryParams?: { [k: string]: any };
items?: MenuItem[]|MenuItem[][];
expanded?: boolean;
disabled?: boolean;
visible?: boolean;
target?: string;
routerLinkActiveOptions?: any;
separator?: boolean;
badge?: string;
badgeStyleClass?: string;
style?:any;
styleClass?:string;
title?: string;
id?: string;
automationId?: any;
}
要构造MegaMenu组件,您必须在打字稿文件中定义结构,由于这不是我的要求,因此我无法脱离它。我也无法从PrimeNG的库中选择另一个菜单组件。希望我的进一步解释对您有所帮助,对不起,如果我起初不清楚。我想重点关注这个问题,而又不会使这个问题复杂化。
this.items = [ //main MenuItem[] contains the entire menu
{
label: label1, visible: this.booleanPipe.transform(this.labelVisible),
items: [ //nested MenuItem[][] contains the headings and each individual menu list for headings
[
{
label: this.label2, visible: this.booleanPipe.transform(this.labelVisible), separator: true,
items: [ //another MenuItem[] (contains dropdowns, subheadings etc)
{ label: this.label3, visible: this.booleanPipe.transform(this.labelVisible) },
希望能够删除最嵌套的内部项目对象的主要原因是,即使您将其可见,Angular仍会在菜单中呈现空白点:false。这使菜单看起来非常非常丑陋且分散。
感谢到目前为止的所有建议并帮助弥补了我的一些知识空白,我将在明天尝试实施所有建议的想法并进行报告。希望我的编辑内容更加清晰。
编辑: 我今天要签约,这是我最近的尝试,但没有成功:
for (let item of this.items) {
for (let subItem of item.items) {
subItem = (subItem as (MenuItem)[]).filter(obj => obj.label !== undefined);
}
}
答案 0 :(得分:1)
使用reduce
创建包含所有元素的单个列表,然后进行过滤。
答案 1 :(得分:1)
使用像这样的递归调用:
private filterItems(items:Array){
return this.items.filter(obj => obj.label !== undefined)
.forEach(item=> if(item.items) {item.items=this.filterArray(item.items)};
}
第一次拨打items=this.filterItems(items)
可能这需要一些修正,因为我在没有编译器帮助的情况下在此处编写了它,但它应该为您提供了一个非常坚实的开端。
答案 2 :(得分:1)
我们很清楚,您的数据如下所示:
interface Item {
label?: string;
visible: boolean;
}
interface MiddleItem {
label?: string;
visible: boolean;
separator: boolean;
items?: Item[];
}
interface TopItem {
label?: string;
visible: boolean;
items?: MiddleItem[][];
}
interface Scope {
items?: TopItem[];
}
要根据您的示例代码来修改原始数据。这样会使算法稍微简单一些(或者,您可以先进行深复制,然后再执行此操作)
您要逐步:
检查标签是否未定义
如果是,请删除该条目
如果不是,则以“相同”方式处理子项
如果只有一个界面,那么以递归的方式进行操作非常容易,但是您的子项都是不同的签名,并且您知道自己的深度,所以让它拼写出来而不是做任何花哨的事情。
从入口点开始:
processScope(this);
function processScope(scope: Scope) {
if(!scope.items) return;
scope.items = scope.items.filter(processTop); // basically your initial start
}
// this function gets called for each array entry in top.items
// normally you see filter as using just the simplified boolean test function
// but here we are going to have it preform a side effect - modifying the contents!
// splitting this out to its own named function makes it easier to read / document
function processTop(top: TopItem): boolean {
if (!top.label) return false; // do not include in filtered array
if (top.items) {
top.items = top.items
.map(processMiddleArr) // process each subarray
.filter(middleArr => middleArr.length !== 0); // map might have replaced the subarray with an empty array - filter those out
return true; // include in filtered array
}
// this gets called for each array entry in top.items
// since top.items is a two dimensional array, this is just another array to iterate
function processMiddleArr(middleArr: MiddleItem[]): MiddleItem[] {
return middleArr.filter(processMiddle);
}
function processMiddle(middle: MiddleItem): boolean {
if (middle.label === undefined) return false; // do not include in filtered array
// here's another side effect, filtering the lowest level item list
if (middle.items) middle.items = middle.items.filter(processItem);
return true; // include in filtered array
}
// broken out into its own function for consistency with the above filter calls
// this would be fine to do inline as middle.items.filter(it => !!item.label)
function processItem(item: Item): boolean {
if (item.label === undefined) return false; // do not include in filtered array
return true; // include in filtered array
}