1
var data = {
  'id': 'object1',
  'sceneCapability': {
  'updatedAt': '2017-06-19T20:52:45.688Z'
    'currentScene': {
      'value': {
        'number': 1,
        'name': '1'
      }
    },
    'outOfTune': {
      'value': false
    }
  },

  'lightingCapability': {
    'intensity': {
      'value': 0
    }
  },

  'tiltCapability': {
    'command': {
      'value': 'NO'
    },
    'position': {
      'value': 0
    }
  }

// like this I have different types of more than 20 Capabilities 
};

How can I write a generic method to parse this Object? I need to get currentScene value, outOfTune, intensity, command, position, etc...

Sometimes I get only one capability and sometime I get more than 20 capabilities.

I want to avoid doing something like this because in future there might be hundreds of different capabilities

if (obj.lightingCapability && obj.lightingCapability.intensity) {
        console.log(obj.lightingCapability.intensity.value)
}

if (device.sceneCapability && device.sceneCapability.outOfTune) {
            // do something
        }

Output I want something like

currentScene:1,
outOfTune: false,
intensity: 0,
command: 'NO',
position: 0
Pratap A.K
  • 4,337
  • 11
  • 42
  • 79

5 Answers5

4

Maybe something like this will work for you?

A helper function that finds the property you need and returns null if anything along the chain doesn't exist. I added two 'different' versions in case you don't like the array of property names.

var object = {
    a: {
        b: {
            c: {
                d: 10
            }
        }
    }
};

function getValue(object, propertyPath) {
    var o = object;
    var pLen = propertyPath.length;

    for (var i = 0; i < pLen; i++) {
        var propertyName = propertyPath[i];
        if (!o.hasOwnProperty(propertyName))
            return undefined;

        o = o[propertyName];
    }

    return o;
}

function getValueFromString(object, path) {
    return this.getValue(object, path.split('.'));
}

console.log(getValue(object, ['a', 'b', 'c', 'd']));    //logs 10
console.log(getValueFromString(object, 'a.b.c.d'));     //logs 10
console.log(getValue(object, ['a', 'b', 'c', 'e']));    //logs undefined
Big Bad Waffle
  • 307
  • 1
  • 6
  • Oh, it looks like you had the same idea and beat me to it. Is there really a benefit to including the wrapper that takes the keys as a string vs just splitting the keys in the getvalue method? – Marie Jun 20 '17 at 14:08
  • So we before calling this method I need to have the keyChain, isn't it? just wondering is there a way to achieve this without knowing the key chain? – Pratap A.K Jun 20 '17 at 14:08
  • 1
    @Marie Not at all. I added the getValueFromString method afterwards in an edit and wanted to keep it short for conciseness. – Big Bad Waffle Jun 20 '17 at 14:10
  • @PratapA.K Are you saying you just want to log out all the 'leaf' properties? (Properties that don't have children themselves) – Big Bad Waffle Jun 20 '17 at 14:12
  • @BigBadWaffle yes something like that. In HTML page I just need to display key and corresponding value. – Pratap A.K Jun 20 '17 at 14:14
  • 1
    @PratapA.K Just the key, or the whole key chain up to there? Maybe just something like JSON.stringify(object) could be useful here? – Big Bad Waffle Jun 20 '17 at 14:15
  • @BigBadWaffle it's just the key. like currentScene - 1, intensity - 0, position - 0, etc.. – Pratap A.K Jun 20 '17 at 14:16
  • 1
    @PratapA.K Check this answer, I think it will do what you want https://stackoverflow.com/questions/34513964/how-to-convert-this-nested-object-into-a-flat-object/34514143#34514143 – Marie Jun 20 '17 at 14:28
3

Based on the discussion we had in the comments of my first answer I realized you meant something different. This should do the trick:

var object = {
    a: {
        b: {
            c: {
                value: 10
            },
            d: {
                e: {
                    value: 20
                }
            }
        }
    }
};

function logAllValues(object) {
    for (var p in object) {
        var o = object[p];
        if (o.value)
            console.log(p + ': ' + o.value);
        else 
            logAllValues(o);
    }
}

logAllValues(object);    //logs c:10 and e:20
Big Bad Waffle
  • 307
  • 1
  • 6
1

A slightly hacky way to do this would be to create a helper function that allows the key chain to be passed in as a string and loop over it. For example

function getValue(obj, keyChain){
  var keys = keyChain.split('.');
  do {
    var key = keys.shift();
    if (!obj.hasOwnProperty(key)){
      return undefined;
    }
    obj = obj[key];
  } while (keys.length > 0);
  return obj;
}

getValue(data, "lightingCapability.intensity.value")
Marie
  • 2,114
  • 1
  • 17
  • 31
  • So we before calling this method I need to have the keyChain, isn't it? just wondering is there a way to achieve this without knowing the key chain? – Pratap A.K Jun 20 '17 at 14:08
  • Sorry, I am not sure I follow. You want to access a specific value without knowing where the value is? – Marie Jun 20 '17 at 14:09
  • yea, it looks bit weird because each capabilities has different parameters. – Pratap A.K Jun 20 '17 at 14:11
0

I think you just need to install lodash#get

npm i --save lodash.get

var get = require('lodash.get');

if(get('foo.baz.foobaz')) {
  alert('yep');
}

but you always will need to know all the paths you need in advance.

Re-implementing this well community tested method will end up in re-inventing the wheel, so, just install and use it.

Hitmands
  • 13,491
  • 4
  • 34
  • 69
-1

you can implement some thing like this using ES6 try and catch block

var object = {
    a: {
        b: {
            c: {
                value: 10
            },
            d: {
                e: {
                    value: 20
                }
            }
        }
    }
};

function getValue(jsObject) {
    try {
        return jsObject();
    } catch (e) {
        return undefined;
    }
}

// use it like this

getValue(() => object.a.b); // returns Object {c: Object, d: Object}

getValue(() => object.a.b.c); // returns Object {value: 10}

getValue(() => object.a.b.x); // returns undefined

CharanRoot
  • 6,181
  • 2
  • 27
  • 45
  • You really shouldnt use a try-catch to control the flow of logic like that. – Marie Jun 20 '17 at 16:09
  • Generally yes. The code is definitely cleaner but negative cases will get a serious performance hit. When possible you should use other logic to avoid the need for a try-catch block. – Marie Jun 20 '17 at 17:14