Ayoub k
Ayoub k

Reputation: 8868

Remove object from array inside a recursive function

I have the following model object:

const model = {
    _id: '1',
    children: [
        {
            id: '2',
            isCriteria: true
        },
        {
            id: '3',
            isCriteria: true
        }
    ]
}

PS: The depth of children is unknown, so I have to use a recursive function to navigate through it.

I want to delete specific objects fro children array based on the array of ids.
So for example if make the following call removeCriteria(model, ['2']), the result should be:

const model = {
    _id: '1',
    children: [
        {
            id: '2',
            isCriteria: true
        }
    ]
}

I implemented this function as follows:

function removeCriteria(node, criteria, parent = []) {
    if (node.isCriteria) {
        if (criteria.length && !criteria.includes(node.id)) {
            parent = parent.filter(criteria => criteria.id !== node.id);
        }
        console.log(parent) // here the parents object is correct but it doesn't modify the original object
    }
    if (node.children)
        for (const child of node.children) removeCriteria(child, criteria, node.children);
}

Upvotes: 0

Views: 549

Answers (2)

awarrier99
awarrier99

Reputation: 3855

The issue is you're reassigning the variable parent, which doesn't accomplish anything since you're not mutating the array to remove objects, and instead you're assigning it to a newly created array. I would suggest introducing a parentObj reference to the object to which parent belongs, so then you can set parentObj.children to parent and actually mutate the original object's array property:

const model = {
    _id: '1',
    children: [
        {
            id: '2',
            isCriteria: true
        },
        {
            id: '3',
            isCriteria: true
        }
    ]
};

function removeCriteria(node, criteria, parent = [], parentObj = {}) {
    if (node.isCriteria) {
        if (criteria.length && !criteria.includes(node.id)) {
            parent = parent.filter(criteria => criteria.id !== node.id);
            parentObj.children = parent;
        }
        console.log('parent', parent) // here the parents object is correct but it doesn't modify the original object
    }
    if (node.children)
        for (const child of node.children) removeCriteria(child, criteria, node.children, node);
}

removeCriteria(model, ['2']);
console.log(model);

Upvotes: 1

Barmar
Barmar

Reputation: 781096

Assigning to parent doesn't assign to the object property where the value came from.

You need to filter node.children and assign back to that property.

function removeCriteria(node, criteria) {
  if (criteria.length == 0) {
    return;
  }
  if (node.children) {
    node.children = node.children.filter(child => !child.isCriteria || criteria.includes(child.id));
    node.children.forEach(child => removeCriteria(child, criteria));
  }
}
const model = {
  _id: '1',
  children: [{
      id: '2',
      isCriteria: true
    },
    {
      id: '3',
      isCriteria: true
    }
  ]
}

removeCriteria(model, ['2']);
console.log(model);

Upvotes: 1

Related Questions