0

How can I pre-populate an JSON-Object which contains some css-properties. Where I need to add all not-contained properties to the previous object and the same for all next up items?

The statement I need:

if (property is not in object) object[property] = $('.foo').css(property);

We have for example an element with the following styling:

.foo {
    top: 0;
    width: 100px;
}

And the following keyframe-alike object:

var keyframe = {
    0: {
        top: 0
    },
    1000: {
        top: 100
    },
    2000: {
        width: 100
    }
};

Here we need to populate all previous items, in this case:

  • 0: width = 0
  • 1000: width = 0

...we get something like this:

var keyframe = {
    0: {
        top: 0,
        width: 0
    },
    1000: {
        top: 100,
        width: 0
    },
    2000: {
        top: 100,
        width: 100
    }
};

...and further, we need to prefill all next items:

  • 2000: top = 100

What results in:

var keyframe = {
    0: {
        top: 0
    },
    1000: {
        top: 100
    },
    2000: {
        top: 100,
        width: 100
    }
};

Our final object needs to be like this one:

var keyframe = {
    0: {
        top: 0,
        width: 0
    },
    1000: {
        top: 100,
        width: 0
    },
    2000: {
        top: 100,
        width: 100
    }
};

Update

T.J. Crowder answer looks good so far, however the problem is that I don't know what properties are in the keyframe-object... So it can be, that there are more/other properties in the keyframe than width and top.

Update2

Currently I've the following:

var $foo = $('.foo');
for (var key in keyframe) {
    var obj = keyframe[key];
    for(var ok in obj) {
        if (!(ok in obj)) obj[ok] = $foo.css(ok);
    }
}

But it seems that

if (!(ok in obj)) // is always `truthy`

however if I do it by declaring it directly

if (!('top' in obj)) // it works...

Any ideas?

Community
  • 1
  • 1
yckart
  • 32,460
  • 9
  • 122
  • 129
  • Check out this answer here it may help you out http://stackoverflow.com/questions/736590/add-new-attribute-element-to-json-object-using-javascript – Banning Jul 16 '13 at 13:07
  • [There is no such thing as a "JSON object'](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/). Your problem does not seem to have anything to do with JSON. You have JavaScript objects. – Felix Kling Jul 16 '13 at 13:24
  • @FelixKling Okay, I agree! It's a JSON-alike thing. But this doesn't help in anyway :P – yckart Jul 16 '13 at 13:25
  • Sure, but proper terminology is important as well ;) – Felix Kling Jul 16 '13 at 13:29

2 Answers2

1

Two thoughts:

  1. Create your keyframe objects with a prototype behind them, e.g.:

    var proto = {top: 0, width: 100};
    var keyframe = {
        0:    Object.create(proto),  // Inherits everything
        1000: Object.create(proto, { // Inherits only width
                  top: {value: 100}
              },
        2000: Object.create(proto, { // Inherits only top
                  width: {value: 100}
              })
    };
    
  2. Do it the manual way, using for-in (spec, article) and in (spec):

    var obj, key;
    for (key in keyframe) {
        obj = keyframe[key];
        if (!('top' in obj)) {
            obj.top = 0;
        }
        if (!('width' in obj)) {
            obj.width = 100;
        }
    }
    

    for-in loops through the names of the enumerable properties of the object. in checks to see if an object as a property with a given name (its own, or on its prototype). In the above, I assumed it was okay for the objects within keyframe to inherit properties.

    If your keyframe objects are every derived from other objects (e.g., they have something other than Object.prototype as their prototype), you'll want to throw a hasOwnProperty in there:

    var obj, key;
    for (key in keyframe) {
        if (keyframe.hasOwnProperty(key)) {
            obj = keyframe[key];
            if (!('top' in obj)) {
                obj.top = 0;
            }
            if (!('width' in obj)) {
                obj.width = 100;
            }
        }
    }
    
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Looks good so far, problem is that I don't know what properties are in the object... So it can be, that there are more properties in the keyframe than `width` and `top`. Any idea how to get this a bit more dynamically? – yckart Jul 16 '13 at 13:11
  • @yckart: Take a first pass through all of the objects, grabbing all of the unique properties, resolving conflicts (e.g., if two objects have different values for the same property) however is appropriate to your problem domain. Then armed with that master list of all properties and the values you want to use for them, do the above. (#1 can still apply, because you can add properties to `proto` as you go, and they magically show up on the objects inherited from it. **But**, you can only assign the prototype when the objects are first created, so that may not work.) – T.J. Crowder Jul 16 '13 at 13:16
  • Mhh, look at my last update, it seems there's just a problem in my logic... Any ideas? – yckart Jul 16 '13 at 13:35
1

This appears to do what you want:

var all = {};

$.each(keyframe, function(_, obj) {
    $.each(obj, function(k) {
        all[k] = 0;
    });
});

$.each(keyframe, function(_, obj) {
    $.each(all, function(k) {
        if(k in obj)
            all[k] = obj[k];
        else
            obj[k] = all[k];
    });
});

console.log(keyframe)
// {"0":{"top":0,"width":0},
// "1000":{"top":100,"width":0},
// "2000":{"width":100,"top":100}}
georg
  • 211,518
  • 52
  • 313
  • 390
  • Great! Looks good so far, problem is that I need to populate the missing properties from the elements styling... See this question: http://stackoverflow.com/questions/17678390/get-iterate-over-properties-that-are-not-in-object – yckart Jul 16 '13 at 14:15