3

I have a Object that contains some (simple) key: value pairs like this:

var things = {
  "0": "apple",
  "1": "mango",
  "2": "pear"
  // ect...
};

Is there a built in function or method in Object.prototype that I can use to listen for a change in the values of the Object?

Maybe something like this:

things.onchange = function() {
  alert(things[Key_Of_Value_That_Changed]);
};

I don't mind using jQuery and browser support isn't a big priority so non-standard and / or custom methods are also welcome.

  • Possible duplicate of [Track whether object changed](http://stackoverflow.com/questions/5952542/track-whether-object-changed) – Božo Stojković Jul 17 '16 at 20:09
  • A great feature that went obsolete ): https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/observe – Roko C. Buljan Jul 17 '16 at 20:09
  • 1
    @Slayther thank you for the link but it does not answer my question. –  Jul 17 '16 at 20:10
  • How does it not answer your question? What doesn't it provide that you need? – Božo Stojković Jul 17 '16 at 20:11
  • @RokoC.Buljan Oh no... Who would get rid of such a great feature..?! –  Jul 17 '16 at 20:11
  • It's a huge problem to implement correctly. In the meantime see: http://stackoverflow.com/questions/1269633/watch-for-object-properties-changes-in-javascript or Goog for similar... https://gist.github.com/melanke/2956493 – Roko C. Buljan Jul 17 '16 at 20:12
  • @Slayther Well, its **far too complicated** for what I need. I have a Object with hundreds (if not thousands) of `key: value` pairs so, making a `get` and `set` method for each of them would be almost *impossible*. –  Jul 17 '16 at 20:14
  • How about general setters and getters? Like `this.set_val = function(key, val) { this[key] = val }` – Božo Stojković Jul 17 '16 at 20:16

4 Answers4

1

You could use a more general setter function, and use that, if applicable (You control setting values).

var things = {
  "0": "apple",
  "1": "mango",
  "2": "pear",
  // ect...

  set_val: function (key, val) {
    this[key] = val;
    this.onchange(key);
  },

  onchange: function () {}
};

things.onchange = function(key) {
  alert(key);
};
Božo Stojković
  • 2,893
  • 1
  • 27
  • 52
  • Thanks. That was my goal. "Well, its **far too complicated** for what I need." – Božo Stojković Jul 17 '16 at 20:26
  • 1
    Thank you for the answer and steering me in the right direction, its greatly appreciated, with a little modification to your code I got just what I wanted. –  Jul 17 '16 at 20:31
1

Normally, you could use a function for setting values and have it called from there, but if you must make sure this gets called on change, you can use a Proxy. This allows you to call a function whenever the property is set.

var trueThings = new Proxy(things, {
  set: // your function here
});

EDIT 10/03/2016:

There's a more widely supported way of forcing it to go through the function, and that is making a shell object that would access the main object using a closure. Just like the Proxy, it wraps the object (which is kept private) and provides tools for manipulating it. You can use the following function to create it:

function makeShell(obj) {
    function setCallback(k, v, obj) {
        // your callback here
    }

    return {
        get: function(k) {
            return obj[k];
        },
        set: function(k, v) {
            setCallback(k, v);
            obj[k] = v;
        }
    }
}
Community
  • 1
  • 1
RamenChef
  • 5,557
  • 11
  • 31
  • 43
0

You can create an element, set element attributes to object properties, use MutationObserver

var things = {
  "prop-0": "apple",
  "prop-1": "mango",
  "prop-2": "pear"
    // ect...
};

var obj = document.createElement("div");

for (var prop in things) {
  obj.setAttribute(prop, things[prop])
};

var target = obj;

var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    things[mutation.attributeName] = obj.getAttribute(mutation.attributeName);
    console.log(obj.getAttribute(mutation.attributeName)
               , things);
  });
});

var config = {
  attributeFilter: Object.keys(things)
};

observer.observe(target, config);

obj.setAttribute("prop-0", "abc");
guest271314
  • 1
  • 15
  • 104
  • 177
0

Here is the final product, and its a modified version of Slayther's answer:

var things = {
  "0": "apple",
  set: function(key, val) {
    var old = (this[key]) ? this[key] : null;
    this["OLD_" + key] = old;
    this[key] = val;
    this.onchange(key, val, old);
  },
  onchange: function(key, value, old) {
    // handle "onchange" business here
  }
};

things.set("0", "pear");

Once again thank you to Slayther, and for those of you who want to see this in action there is a demo over on Codepen.

Community
  • 1
  • 1