Home > Mobile >  Toggling checkboxes using recursion | Recursion problem
Toggling checkboxes using recursion | Recursion problem

Time:06-28

I am trying to implement a checkbox tree that has the following data structure for items

const checkboxes = [{
    field: 'ARTICLE',
    id: 41,
    name: 'Article',
    parentId: null,
    checked: false,
    children: [
      {
        field: 'article.colorCode',
        id: 42,
        name: 'Color',
        parentId: 41,
        checked: false,
        children: [
          {
            children: [],
            field: 'red',
            id: 43,
            name: 'red',
            parentId: 42,
            checked: false
          },
        ],
      },
    ],
  }]

Whenever I click on Article when it's unchecked, it should set checked property as true for Article and nested children and vice-versa.

Can someone please help me with a recursive function so that no matter what the depth of children is, all children get toggled? I just can't undrestand recursion.

CodePudding user response:

I would break this down into three pieces. First, we need to be able to walk our nodes and alter the appropriate ones. Second, we need a way to, starting with some node in the hierarchy, invert the checked property on that node and pass this new value down through all its descendents. Third, we need to put this together with something that checks the nodes' ids to find where to start this process.

Here is a version which breaks it down this way:

const alterNodes = (pred, trans) => (nodes) => nodes .map (
  node => pred (node) ? trans (node) : {...node, children: alterNodes (pred, trans) (node .children)}
)

const checkHierarchy = ({checked, children, ...rest}, value = !checked) => ({
  ... rest,
  checked: value,
  children: children .map (child => checkHierarchy (child, value))
})

const toggleHierarchy = (targetId, checkboxes) =>
  alterNodes (({id}) => id == targetId, checkHierarchy) (checkboxes)

const checkboxes = [{field: 'ARTICLE', id: 41, name: 'Article', parentId: null, checked: false, children: [{field: 'article.colorCode', id: 42, name: 'Color', parentId: 41, checked: false, children: [{children: [], field: 'red', id: 43, name: 'red', parentId: 42, checked: false}]}]}]

console .log (toggleHierarchy (41, checkboxes))
.as-console-wrapper {max-height: 100% !important; top: 0}

CodePudding user response:

Since you mentioned react, I assume you prefer immutable way to do that, since that tree might be stored in state.

The function you want to use is: toggleNodeInsideTree function, and you should pass it id of the node you want to toggle, and tree data.

 let data = [
    {
      field: 'ARTICLE',
      id: 41,
      name: 'Article',
      parentId: null,
      checked: false,
      children: [
        {
          field: 'red',
          id: 43,
          name: 'red',
          parentId: 41,
          checked: false,
        },
        {
          field: 'article.colorCode',
          id: 42,
          name: 'Color',
          parentId: 41,
          checked: false,
          children: [
            {
              children: [],
              field: 'test',
              id: 44,
              name: 'red',
              parentId: 42,
              checked: false,
            },
          ],
        },
      ],
    },
    {
      children: [],
      field: 'red',
      id: 45,
      name: 'red',
      parentId: 41,
      checked: false,
    },
  ];

  let setCheckedValueForNodeAndChildren = (item, value) => {
    if (item.children) {
      return {
        ...item,
        checked: value,
        children: item.children.map((x) =>
          setCheckedValueForNodeAndChildren(x, value)
        ),
      };
    } else {
      return { ...item, checked: value };
    }
  };

  let toggleNodeInsideTree = (id, tree) => {
    return tree.map((x) => {
      if (x.id === id) {
        return setCheckedValueForNodeAndChildren(x, !x.checked);
      }

      if (x.children) {
        return { ...x, children: toggleNodeInsideTree(id, x.children) };
      }

      return x;
    });
  };

  console.log(toggleNodeInsideTree(42, data));

  • Related