0

I have an nested JSON object like this:

var jsonObj = 
{ "level1" : 
      { "status" : true,
        "level2" : {} // and it has the same format and can go to level3, 4, etc
       }
}

What I want to do is simple, I want to get to Level2, and add a new Level3 object to it. Basically I want to do the following code below, but since the levels are dynamic, I need a function that traverse my object.

obj.Level1.Level2.Level3 = { 'status' : true}

Here's my snippet of code:

function updateStatusForLevel(nestedObj, categoryHierarchy){
        // categoryHierarchy that is passed = ['Level1', 'Level2', 'Level3']; 
        var obj = nestedObj;

        angular.forEach(categoryHierarchy, function(value, key){
            obj = obj[value];


            if (key === categoryHierarchy.length - 1 && angular.isUndefined(obj)){
                 obj[value] = {}; // I want to add 'Level3' = {}
            }
        });
        obj.status = 'true'; // and finally, update the status 
        console.info("my original obj is " + JSON.stringify(nestedObj));
    }

However seems like I'm missing something. If I do this, my original nestedObj is still the same as what I'm passing in (it's not updated, only the obj object is updated. I believe this should be a really simple code that traverse a nested JSON object. Why is the shallow copy not updating the original object?

6
  • can you provide a plunkr link ? Commented Jul 27, 2015 at 5:21
  • obj[value].status = 'true'; u r accessing value outside the foreach. Commented Jul 27, 2015 at 5:23
  • 1
    what is objHierarchy in foreach? Commented Jul 27, 2015 at 5:30
  • @manivannan sorry I copied the code and changed some variables name to be simple, but i changed some incorrectly. code is updated Commented Jul 27, 2015 at 5:41
  • can't u provide plunker? i think obj is undefined. because u r assigning obj[value] aftet obj was assigned. obj = obj[value]; put this line after if condition in foreach\. Commented Jul 27, 2015 at 5:48

2 Answers 2

1

Maybe like this

function updateStatusForLevel(nestedObj, categoryHierarchy){
        // categoryHierarchy that is passed = ['Level1', 'Level2', 'Level3']; 
        if(categoryHierarchy.length) {
             var shifted = categoryHierarchy.shift();
             nestedObj[shifted] = {status: true};
             return updateStatusForLevel(starter[shifted], categoryHierarchy);
       } else {
             return nestedObj;
       }
}

Then calling updateStatusForLevel(nestedObj, ['level1', 'level2', 'level3']) will modify nestedObj as

level1: Object
    level2: Object
        level3: Object
            status: true
        status: true
    status: true

note, this answer is not clever, so better have plnkr or something for better asnwer, but for now, try this in browser dev console

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

Comments

0

Since you only want to add a value from a certain path of nested objects, then how about creating a generic function that can do this, instead of creating a custom one. I have created a factory named helper, which can be a collection of helper functions that you may want to add later on.

DEMO

JAVASCRIPT

  .factory('helper', function() {

    var helper = {};

    helper.set = function(object, path, value) {

      // save reference of an object
      var reference = object,
          // last key n the path
          lastKey;

      path = angular.isArray(path)? path: // set as an array if it is an array
          angular.isString(path)? path.split('.'): // split the path as an array if it is a string
          false; // set to false and do nothing if neither of the conditions above satisfies

      // check if path is truthy
      if(path) {

        // get the last key of the path
        lastKey = path.pop();

        // reduce the references until all the remaining keys
        reference = path.reduce(function(reference, key) {

          // check if the current object reference is undefined
          if(angular.isUndefined(reference[key])) {
            // set current object reference as an object if it is undefined
            reference[key] = {};
          }

          // return the current object reference for the next iteration
          return reference[key];

        }, reference); 

        // set the last object reference for the value
        reference[lastKey] = value;

      }

      return object;

    };

    return helper;

  })

  .run(function(helper) {

    var object1 = {},
        object2 = {},
        object3 = {},

        object4 = { 
          "level1" : { 
            "status" : true,
            "level2" : {}
          }
        };

    helper.set(object1, 'z.k.v.q', { status: false });
    // object1 = { z: { k: { v: { q: { status: false } } } } }
    console.log(object1);

    helper.set(object2, 'a.e.i.o.u', { status: true });
    // object2 = { a: { e: { i: { o: { u: { status: true } } } } } }
    console.log(object2);

    helper.set(object3, ['hello', 'world'], { status: undefined });
    // object3 = { hello: { world: { status: undefined } } }
    console.log(object3);

    helper.set(object4, 'level1.level2.level3', { status: true });
    // object4 = { status: true, level1: { level2: { level3: { status: true } } } }
    console.log(object4);

  });

Alternatively, you can use lodash for this, and you'd be able to do more object, array and collection manipulation. The lodash function you should be looking for would be _.set()

DEMO

JAVASCRIPT

  .service('_', function($window) {
    // you can add mixins here
    // read more about lodash if you
    // want to customize data manipulation
    return $window._;
  })

  .run(function(_) {

    var object1 = {},
        object2 = {},
        object3 = {},

        object4 = { 
          "level1" : { 
            "status" : true,
            "level2" : {}
          }
        };

    _.set(object1, 'z.k.v.q', { status: false });
    // object1 = { z: { k: { v: { q: { status: false } } } } }
    console.log(object1);

    _.set(object2, 'a.e.i.o.u', { status: true });
    // object2 = { a: { e: { i: { o: { u: { status: true } } } } } }
    console.log(object2);

    _.set(object3, ['hello', 'world'], { status: undefined });
    // object3 = { hello: { world: { status: undefined } } }
    console.log(object3);

    _.set(object4, 'level1.level2.level3', { status: true });
    // object4 = { status: true, level1: { level2: { level3: { status: true } } } }
    console.log(object4);

  });

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.