问题
i have problem looping through a nested array that can contains arrays of itself... that should represent a dynamic menu as follow:
this is how the objects are made:
Interface IMenuNode:
export interface IMenuNode {
title: string;
haveChildren: boolean;
id: string;
node: Array<IMenuNode>;
link: string;
img: string;
value: string;
}
Class DataNode that implements IMenuNode
export class DataNode implements IMenuNode {
title: string;
haveChildren: boolean;
id: string;
node: Array<IMenuNode>;
link: string;
img: string;
value: string;
userMenu: Array<IMenuNode>;
Now i have some informations in the MenuData as follow:
const MenuData: Array<IMenuNode> =
[
new DataNode('Menu 1', true, 'menu1', [
new DataNode('SubMenu 1', true, 'submenu1',[
new DataNode('SubSubMenu1', false ,'subsubmenu1', null, "/", "pathSelectorIcon.png"),
new DataNode('SubSubmenu2', false, 'subsubmenu2', null ,"/", "pathSelectorIcon.png"),
]),
new DataNode('Menu 2', true, 'menu2', [
new DataNode('SubMenu 1', true, 'submenu1',[
new DataNode('SubSubMenu1', false ,'subsubmenu1', null, "/", "pathSelectorIcon.png"),
new DataNode('SubSubmenu2', false, 'subsubmenu2', null ,"/", "pathSelectorIcon.png"),
]),
How can i loop the entire MenuData (even recursively) and dynamically build a new menu (userMenu) based on some conditions to choose which items (menu and submenu) the new menu should have of?
回答1:
The function below apparently do what you expect, hope it helps.
userMenu = newUserMenu(MenuData);
function newUserMenu(original: Array<IMenuNode>): Array<IMenuNode> {
const newMenu: Array<IMenuNode> = []
for (let menu of original) {
if (User.hasAccess(menu)) { // Or other conditions
// To ensure new reference
// Note not passing the children, it must pass through recursive method below
const newNode = new DataNode(menu.title, menu.haveChildren, menu.id, null, menu.link, menu.img, menu.value);
newMenu.push(newNode);
if (newNode.haveChildren) {
newNode.node = newUserMenu(menu.node);
}
}
}
return newMenu;
}
I've edited your class and interface too, to ensure that the construction works like the example.
interface IMenuNode {
title: string;
haveChildren: boolean;
id: string;
node?: Array<IMenuNode>;
link?: string;
img?: string;
value?: string;
}
class DataNode implements IMenuNode {
constructor(
public title: string,
public haveChildren: boolean,
public id: string,
public node?: Array<IMenuNode>,
public link?: string,
public img?: string,
public value?: string,
) { }
}
Edit: new example validating the children before adding current level on new menu.
// The new function only add the "dir" menus if they have children where the user have access
function newUserMenu2(original: Array<IMenuNode>): Array<IMenuNode> {
const newMenu: Array<IMenuNode> = [];
for (let menu of original) {
if (User.hasAccess(menu)) {// Or other conditions
// To ensure new reference
// Note not passing the children, it must pass through recursive method below
const newNode = new DataNode(menu.title, menu.haveChildren, menu.id, null, menu.link, menu.img, menu.value);
if (newNode.haveChildren) {
newNode.node = newUserMenu2(menu.node);
}
// Note, only add the menu if it has a link or if it "stores" a menu that the user has access and that has a link
if (Array.isArray(newNode.node) && newNode.node.length > 0 || newNode.link) {
newMenu.push(newNode);
}
}
}
return newMenu;
}
来源:https://stackoverflow.com/questions/58838567/typescript-recursive-check-nestest-arrays