0

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);
}
5
  • Shouldn't the result of removeCriteria(model, ['2']) be the object with id 3? Commented Jun 12, 2020 at 1:48
  • @awarrier99 No, I want to keep the object that exists in that given array. Commented Jun 12, 2020 at 1:50
  • 2
    Perhaps you should rename your function keepCriteria. Commented Jun 12, 2020 at 1:56
  • @Nick But I'm removing criteria based on an array, the criteria that don't exist on that array get removed. Commented Jun 12, 2020 at 1:58
  • 1
    No you're right, that's not the issue at all, but typically one passes a value to a remove function that one wants to remove, not to keep. Commented Jun 12, 2020 at 1:59

2 Answers 2

1

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);

Sign up to request clarification or add additional context in comments.

Comments

1

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.