1

Given a nested object like:

var x = {
    'name': 'a',
    'testObj': {
        'blah': 8,
        'testObj2': { // delete this obj
            'blah2': 9,
            'blah3': 'c'
            }
        },
    'level': 1,
    'children': [{
        'name': 'b',
        'level': 2,
        'children': [{ // delete this obj
            'name': 'c',
            'level': 3
        }]}]
};

how does one go about deleting a nested object if it contains a property with a value (in my example, the string 'c') one specifies within a function? With the end result being like this:

var x = {
    'name': 'a',
    'testObj': {
        'blah': 8,
        },
    'level': 1,
    'children': [{
        'name': 'b',
        'level': 2,
        'children': []}]
};

Here's my code thus far:

function recursiveIteration(obj, callback) {
    var k;
    if (obj instanceof Object) {
        for (k in obj){
            if (obj.hasOwnProperty(k)){
                recursiveIteration( obj[k], callback );  
            }                
        }
    } else {
        callback(obj); // this is the non-object val
    }
}
function deleteObjByValue(object, word) {
    return recursiveIteration(object, function(val) {
        if (word === val){
            // here I want to delete the nested object (not the whole object) that contains the property with this val assigned to it
        }else {
            return false;
        }
    });
}
deleteObjByValue(x, 'c');
Brandon Minton
  • 994
  • 3
  • 13
  • 25

3 Answers3

3

Loop through the properties in the object first, to check if it should be deleted. If it should, return true so that the calling function can delete it (as you can't delete a property with just the value of the property). If it shouldn't be deleted, loop through the properties that are objects to check if any of them should be deleted:

function deleteObjByValue(obj, value) {
    var k;
    for (k in obj){
        if (obj.hasOwnProperty(k)){
            if (obj[k] === value) {
                return true;
            }
        }                
    }
    for (k in obj){
        if (obj.hasOwnProperty(k) && obj[k] instanceof Object){
            if (deleteObjByValue(obj[k], value)) {
                delete obj[k];
            }
        }
    }
    return false;
}

Demo: http://jsfiddle.net/hbHGM/

Note: If the main object has a property that matches the value, the function won't delete anything. It will just return true to signify that the entire object should go away. You would handle it something like this:

if (deleteObjByValue(x, 'c')) {
  x = null; // or whatever you want to do
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
1

The proper way to delete properties from objects is to call the delete function. Thus you need a little refactoring in your code, something like (untested):

function recursiveIteration(parent, key, callback) {
    var obj = parent[key];
    var k;
    if (obj instanceof Object) {
        for (k in obj){
            if (obj.hasOwnProperty(k)){
                recursiveIteration( obj, k, callback );  
            }                
        }
    } else {
        callback(parent, key); // this is the non-object val
    }
}
function deleteObjByValue(object, word) {
    return recursiveIteration({object: object}, 'object', function(obj, key) {
        if (word === obj[key]){
            delete obj[key];
        }else {
            return false;
        }
    });
}
deleteObjByValue(x, 'c');
Anthony Garcia-Labiad
  • 3,531
  • 1
  • 26
  • 30
1

You need to keep a reference to the parent of the object that determines whether or not you delete it.

Here's a solution:

function deleteParentByValue(object, object_parent, value) {
    for (var x in object) {
        if (object.hasOwnProperty(x)) {
            if (typeof(object[x]) === 'object') {
                deleteParentByValue(object[x], object, value);
            } else {
                if (object[x] == value) {
                    for (var z in object_parent) {
                        if (object_parent[z] == object) {
                            if (object_parent instanceof Array) {
                                object_parent.splice(object_parent.indexOf(z), 1);
                            } else {
                                delete object_parent[z];
                            }
                        }
                    }
                    break;
                }
            }
        }
    }
}

function deleteObjByValue(object, word) {
    return deleteParentByValue(object, null, word);
}
sahbeewah
  • 2,690
  • 1
  • 12
  • 18
  • I would like to point out that the line `object_parent.splice(object_parent.indexOf(z), 1);` will always remove the last item of the `object_parent` array. `object_parent.indexOf(z)` will always return -1 since you are looking for an integer in the `object_parent` object instead of the `object` itself. An updated line would be `object_parent.splice(z, 1);`, seeing as you already have the index `z` from the `for` loop. – wikenator Aug 16 '22 at 20:51