Ross Zurowski
Ross Zurowski

Reputation: 958

Object defineProperty setter for properties

Using NodeJS, I'm trying to keep track of changes to Model attributes regardless of what type they may be. Using Object.defineProperty setters usually work great, but for Objects and arrays, if a property of the object is set I'm unable to track changes that are made.

I realize that the setter isn't the object itself, but is there a way I can get it to function as though it is?

For example, can I get the below code to trigger the setter when a "property" of the setter is set?

var model = {};
model.attributes = {};

Object.defineProperty(model, 'options', {
    get: function() {
        return this.attributes.options;
    },
    set: function(value) {
        console.log('changed options from:', this.attributes.options, 'to', value);
        this.attributes.options = value;
    }
});

model.options = {};
model.options = { a: 50 }; // triggers setter
model.options.b = 60;      // doesn't trigger setter, how can I get it to do so?

Upvotes: 0

Views: 1018

Answers (1)

Karamell
Karamell

Reputation: 1032

If you're using an ES6 transpiler that supports proxies, you can solve the problem like the so:

var handler = {
  defineProperty (target, key, descriptor) {
    console.log('changed options from:', target[key], 'to', descriptor.value);
    if(typeof descriptor.value === 'object'){
        descriptor.value = new Proxy(descriptor.value,handler);
    }
    Object.defineProperty(target, key, descriptor);
    return true;
  }
}

var target = {}
var proxy = new Proxy(target, handler)

proxy.foo = 'bar2'        // changed from undefined to bar2
proxy.foo = 'bar'         // changed from bar2 to bar
proxy.options = { a: 50 } // changed from undefined to Object { a: 50 }
proxy.options.a = 15      // changed from 50 to 15
proxy.options.b = 60      // changed from undefined to 60

Inspired by this article

Upvotes: 4

Related Questions