skip to Main Content

I have this kind of array (i call it categories, these have childCats too)

var cats = [
  {
      "id": 1,
      "name": "A",
      "parentCategoryId": null,
      "parentCategory": null,
      "childCategories": [
          {
              "id": 2,
              "name": "B",
              "parentCategoryId": 1,
              "parentCategory": null,
              "childCategories": [
                  {
                      "id": 3,
                      "name": "C",
                      "parentCategoryId": 2,
                      "parentCategory": null,
                      "childCategories": []
                  },
                  {
                      "id": 4,
                      "name": "D",
                      "parentCategoryId": 2,
                      "parentCategory": null,
                      "childCategories": []
                  },
                  {
                      "id": 5,
                      "name": "E",
                      "parentCategoryId": 2,
                      "parentCategory": null,
                      "childCategories": []
                  }
              ]
          }
      ]
  },
  {
      "id": 66,
      "name": "BLA",
      "parentCategoryId": null,
      "parentCategory": null,
      "childCategories": []
  },  
  
];

What i now need is to get an array with checked items (and its parents)

This means, i checked only "C", i get:

[
  {
      "name": "A",
      "childCategories": [
          {
              "name": "B",
              "childCategories": [
                  {
                      "name": "C",
                      "childCategories": []
                  }
              ]
          }
      ]
  }
]

if i checked "C" and "D":

var cats = [
  {
      "name": "A",
      "childCategories": [
          {
              "name": "B",
              "childCategories": [
                  {
                      "name": "C",
                      "childCategories": []
                  },
                  {
                      "name": "D",
                      "childCategories": []
                  }
              ]
          }
      ]
  },    
];

and for "B" this:

var cats = [
  {
      "name": "A",
      "childCategories": [
          {
              "name": "B",
              "childCategories": []
          }
      ]
  },    
];

What i currently have (and it feels like a mess) is that: (result in console.log(..))

console.clear();
var checkedInterests = ['C'];
var checkedInterestsForDisplay = [];

var getInterestsForDisplay = function(arr) {
  for (var a of arr) {
    if (checkedInterests.includes(a.name)) {
      a.childCategories = [];
      checkedInterestsForDisplay.push(a);

      //also if a child is checked, the parent should be expanded
      var getParents = function(arrayToFindParent, parentIdToFind) {
        for (var aTFP of arrayToFindParent) {
          if (aTFP.id == parentIdToFind) {
            aTFP.childCategories = checkedInterestsForDisplay;
            checkedInterestsForDisplay = [aTFP];
            //again check if it has parents
            getParents(cats, aTFP.parentCategoryId);
          } else {
            getParents(aTFP.childCategories, parentIdToFind);
          }
        }
      }
      getParents(cats, a.parentCategoryId);
    }
    getInterestsForDisplay(a.childCategories);
  }
}

getInterestsForDisplay(cats);

console.log('checkedInterestsForDisplay', checkedInterestsForDisplay);
<script>
var cats = [{
    "id": 1,
    "name": "A",
    "parentCategoryId": null,
    "parentCategory": null,
    "childCategories": [{
      "id": 2,
      "name": "B",
      "parentCategoryId": 1,
      "parentCategory": null,
      "childCategories": [{
          "id": 3,
          "name": "C",
          "parentCategoryId": 2,
          "parentCategory": null,
          "childCategories": []
        },
        {
          "id": 4,
          "name": "D",
          "parentCategoryId": 2,
          "parentCategory": null,
          "childCategories": []
        }
      ]
    }]
  },
  {
    "id": 66,
    "name": "BLA",
    "parentCategoryId": null,
    "parentCategory": null,
    "childCategories": []
  },
];
</script>

this works oky, but if

var checkedInterests = ['C','D'];

i get

Maximum call stack size exceeded

2

Answers


  1. You could simplify the code to get the items from children, or check the actual root. If either has some wanted items return the object with filtered children.

    const
        data = [{ id: 1, name: "A", parentCategoryId: null, parentCategory: null, childCategories: [{ id: 2, name: "B", parentCategoryId: 1, parentCategory: null, childCategories: [{ id: 3, name: "C", parentCategoryId: 2, parentCategory: null, childCategories: [] }, { id: 4, name: "D", parentCategoryId: 2, parentCategory: null, childCategories: [] }, { id: 5, name: "E", parentCategoryId: 2, parentCategory: null, childCategories: [] }] }] }, { id: 66, name: "BLA", parentCategoryId: null, parentCategory: null, childCategories: [] }],
        filter = (data, names) => data.reduce((r, o) => {
            const
                childCategories = filter(o.childCategories, names);
                
            if (names.includes(o.name) || childCategories.length) r.push({ ...o, childCategories });
            
            return r;
        }, []);
        
    console.log(filter(data, ['A']));
    console.log(filter(data, ['B']));
    console.log(filter(data, ['C', 'D']));
    console.log(filter(data, ['BLA', 'C', 'D']));
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  2. Here’s a simplified recursive approach. I assume the result should be the same if you check A and C as if you just checked C.

    console.clear();
    var checkedInterests = ['B','BLA'];
    
    const getInterestsForDisplay = (arr) => 
      arr.reduce((acc, el) => {
        // get a list of checked children (recursive call)
        const children = el.childCategories?.length 
          ? getInterestsForDisplay(el.childCategories)
          : [];
        
        // either this element is checked, or a child is checked, to be added to output.  
        if (checkedInterests.includes(el.name) || children.length) {
          acc.push({...el, childCategories: children});
        }
        
        return acc;
      }, []);
    
    const checkedInterestsForDisplay = getInterestsForDisplay(cats);
    console.log(checkedInterestsForDisplay);
    <script>
    var cats = [{
        "id": 1,
        "name": "A",
        "parentCategoryId": null,
        "parentCategory": null,
        "childCategories": [{
          "id": 2,
          "name": "B",
          "parentCategoryId": 1,
          "parentCategory": null,
          "childCategories": [{
              "id": 3,
              "name": "C",
              "parentCategoryId": 2,
              "parentCategory": null,
              "childCategories": []
            },
            {
              "id": 4,
              "name": "D",
              "parentCategoryId": 2,
              "parentCategory": null,
              "childCategories": []
            }
          ]
        }]
      },
      {
        "id": 66,
        "name": "BLA",
        "parentCategoryId": null,
        "parentCategory": null,
        "childCategories": []
      },
    ];
    </script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search