Search code examples
javascriptrecursiontreeview

How to do recursive tree array function?


I have an infinitely deep folders tree-array. Each folder have a "hasPermission" boolean. What I want to achieve is when a parent folder's (that can be located anywhere in the tree) "hasPermission" changes, all it's children "hasPermission" will also change - of course, the grandparent folders "hasPermission" will not change.

For example, in the folder tree below. If folderId: '2.1' changes permission, folderId: '3.1' will also change; the others will stay the same.

const example = [
  {
    folderId: '1',
    hasPermission: false,
    children: [
      {
        folderId: '2.1',
        hasPermission: false,
        children: [
          {
            folderId: '3.1',
            hasPermission: false,
            children: [],
          },
        ],
      },
      {
        folderId: '2.2',
        hasPermission: false,
        children: [],
      },
    ],
  },
];

This function changes the "hasPermission" recursively.

  const changeChildrenPermission = (
    folders
  ) => {
    return folders.map(
      ({ id, children, hasPermission }) => ({
        id,
        hasPermission: (hasPermission === false && true) || false,
        children: changeChildrenPermission(children),
      })
    );
  };

Here is what I have so far, I'm trying to look up the tree for the selectedId, if it matches, then call the "changeChildrenPermission" function.

  const setPermissionChange = (
    folders,
    selectedId
  ) => {
    const a = folders.map((folder) => {
      if (folder.id === selectedId) {
       return {
          id: folder.folderId,
          hasPermission: (hasPermission === false && true) || false,
          children: changeChildrenPermission(folder.children),
        };
    });
  };

Not sure what to do afterwards.


Solution

  • // visitFolders: Walks the folder tree recursively and calls visitFolder for every folder.
    // - If visitFolder returns true for a folder, the walk stops immediately.
    // - If you want to visit all folders, visitFolder should return false.
    //   (Returning false can be omitted, because the default return value of functions is undefined, which is falsy.)
    const visitFolders = (folders, visitFolder) => {
      for (let folder of folders) {
        if (visitFolder(folder) || visitFolders(folder.children, visitFolder)) {
          return true;
        }
      }
      return false;
    };
    
    const findFolderById = (folders, id) => {
      let folderWithId = null;
      visitFolders(folders, folder => {
        if (folder.id === id) {
          folderWithId = folder;
          return true;
        }
        return false;
      });
      return folderWithId;
    };
    
    const setFolderPermission = (folder, hasPermission) => {
      visitFolders([folder], folder => {
        folder.hasPermission = hasPermission;
        return false;
      });
    };
    
    const folders = [
      {
        id: "1",
        hasPermission: true,
        children: [
          {
            id: "1.1",
            hasPermission: true,
            children: []
          },
          {
            id: "1.2",
            hasPermission: true,
            children: [
              {
                id: "1.2.1",
                hasPermission: true,
                children: []
              },
              {
                id: "1.2.2",
                hasPermission: true,
                children: []
              }
            ]
          },
          {
            id: "1.3",
            hasPermission: true,
            children: []
          },
          {
            id: "1.4",
            hasPermission: true,
            children: []
          }
        ]
      },
      {
        id: "2",
        hasPermission: true,
        children: [
          {
            id: "2.1",
            hasPermission: true,
            children: []
          },
          {
            id: "2.2",
            hasPermission: true,
            children: []
          }
        ]
      }
    ];
    
    const folder = findFolderById(folders, "1.2");
    if (folder !== null) {
      setFolderPermission(folder, false);
    }
    visitFolders(folders, folder => {
      console.log(folder.id, folder.hasPermission);
      return false;
    });