Sakuto Sakuto - 8 days ago 4
Javascript Question

Access second level child in Json based on a variable

I'm currently working on a configuration service in my Angular 2 application, my current concern is about the utilization of eval in my code to retrieve a value in my configuration.

Here's a sample of my configuration file:

{
"application": {
"environment": "dev",
"displayMenu": false
},

"error": {
"title": "Title Error",
"message": "Error message"
}
}


I'm retrieving this JSON with a simple HTTP request, but now I would like to access an element with my get method defined like this:

get(key: any) {
return (eval("this._config." + key));
}


As you can see, there is an eval in my code that I would like to avoid. I'm forced to use eval to allow the developer to do .get('application.environment') and actually I don't find any others an easy possibility.

The only other way that I could see is to split the key on a "." and retrieve the right element in my JSON like it was a simple array. But with this solution, I would be stuck to one depth only.

Answer

You could use an array of your object keys you wish to view, then reduce that array returning the key of the object. If you wish to have a string as the object accessors you can easily use string.split('.') to create the array you can reduce.

const data = {
  "application": {
    "environment": "dev",
    "displayMenu": false
  },
  "error": {
    "title": "Title Error",
    "message": "Error message",
    "deeper": {
      "evenDeeper": "You can get to any level"
    }
  }
}

const path = (keys, obj) => {
  return keys.reduce((obj, key) => {
    return typeof obj !== 'undefined' 
      ? obj[key]
      : void 0
  }, obj)
}

console.log(
  path(['application', 'environment'], data)
)
console.log(
  path('error.message'.split('.'), data) // move the split inside the path function
)
console.log(
  path(['error', 'deeper', 'evenDeeper'], data)
)
console.log(
  path(['error', 'fail', 'damn'], data) // fail safe
)
<script src="http://codepen.io/synthet1c/pen/WrQapG.js"></script>