adding to json property that may or may not exist yet

17,251

Solution 1

Define get and set methods on an Object. Actually it could be defined just on the dashboard object and only its descendants, but that's easy to do.

Object.prototype.get = function(prop) {
    this[prop] = this[prop] || {};
    return this[prop];
};

Object.prototype.set = function(prop, value) {
    this[prop] = value;
}

Iterate through nested properties using this get() method and call set() whenever a value has to be set.

var dashboard = {};

dashboard.get('pages').get('user').set('settings', 'oh crap');
// could also set settings directly without using set()
dashboard.get('pages').get('user').settings = 'oh crap';

console.log(dashboard); //​​​​​​​​​​​​​​​ {pages: {user: {settings: "oh crap"}}};

You could also extend/modify the get method to accept the nested properties as individual arguments or an array or a string. Using that, you'd only have to call get once:

// get accepts multiple arguments here
dashboard.get('pages', 'user').set('settings', 'something');

// get accepts an array here
dashboard.get(['pages', 'user']).set('settings', 'something');

// no reason why get can't also accept dotted parameters
// note: you don't have to call set(), could directly add the property
dashboard.get('pages.user').settings = 'something';

Update:

Since the get method generically returns an object and does not know whether you need an array or some other type of object, so you would have to specify that yourselves:

dashboard.get('pages.user').settings = [];

Then you could push items to the settings array as

dashboard.get('pages.user').settings.push('something');
dashboard.get('pages.user').settings.push('something else');

To actually have the get function construct the object hierarchy from a given string such as pages.user, you would have to split the string into parts and check if each nested object exists. Here is a modified version of get that does just that:

Object.prototype.get = function(prop) {
    var parts = prop.split('.');
    var obj = this;
    for(var i = 0; i < parts.length; i++) {
        var p = parts[i];
        if(obj[p] === undefined) {
            obj[p] = {};
        }
        obj = obj[p];
    }
    return obj;
}

// example use
var user = dashboard.get('pages.user');
user.settings = [];
user.settings.push('something');
user.settings.push('else');

console.log(dashboard); // {pages: {user: {settings: ["something", "else"] }}}

// can also add to settings directly
dashboard.get('pages.user.settings').push('etc');

Solution 2

I would do it with the ternary operator:

dashboard['pages'][page] = dashboard['pages'][page] ? dashboard['pages'][page] : {};

That will do the trick no matter if it's set/null or whatever.

Solution 3

I don't think there's a good builtin way to do this, but you could always abstract it with a function.

function getProperty(obj,prop){
    if( typeof( obj[prop] ) == 'undefined' ){
        obj[prop] = {};
    }
    return obj[prop];
}

Then you use

getProperty(dashboard,'pages')['pagename']

or

getProperty(getProperty(dashboard,'pages'),'pagename');

As mentioned, $.extend will make this less burdensome.

Solution 4

The best solution for my case was to do a Object prototype

 /**
 * OBJECT GET
 * Used to get an object property securely
 * @param object
 * @param property
 * @returns {*}
 */
Object.get = function(object, property) {
    var properties = property.split('.');
    for (var i = 0; i < properties.length; i++) {
        if (object && object[properties[i]]) {
            object = object[properties[i]];
        }
        else {
            return null;
        }
    }
    return object;
};

And then you can get your property like this

var object = { step1: { step2: { step3: ['value1', 'value2'] }}}
Object.get(object, 'step1.step2.step3'); // ['value1', 'value2']
Object.get(object, 'step1.step2.step3.0'); // 'value1'
Object.get(object, 'step1.step2.step3.step4'); // null

Hope it helps :)

Share:
17,251

Related videos on Youtube

mcgrailm
Author by

mcgrailm

Hello, thanks for visiting my profile. I am a web developer at PSU. I started my carrier by learning applescript. Since then I've become familiar with PHP MySQL, javascript, jQuery as well. I have made use of other services that go hand and hand with those languages such as json,jsonp,ajax. I have some shell scripting experience and have dabbled in perl. Hopefully I have helped you with a question you or maybe you have help me with a question, thanks for stopping by.

Updated on April 18, 2022

Comments

  • mcgrailm
    mcgrailm about 2 years

    let say I want to do this:

      var dashboard = {};
      var page = "index";
    
      $('.check').click(function(){ 
        $(this).toggleClass("active").siblings().slideToggle('slow', function() {
            dashboard['pages'][page][$(this).closest('li').attr("id")]['show'] = $(this).is(":hidden") ? 'collapsed' : 'expanded';
        });
      }
    

    I get an error saying:

    Dashboard.pages is undefined

    Is there away to dynamically add pages and the children that follow without having to do the work of checking to see if it is defined first then if it's not doing:

       dashboard['pages'] = {};
    

    because sometimes they may already exist and I don't want to have to inspect the tree first I just want to build the branches as needed

    EDIT I changed pagename to page to show that page names will change and also I want to point out that the pages could really be anything too. The idea is that you have any object that can contain objects with parameters without checking to see if the branches exist

    It looks like $extend as stated will be the way to go just not sure how that works. Got to get my head around that.