15

Is there a way in JavaScript to have something like an event that listens to changes in a variable? So when its value is modified, the event triggers and then I can call a function. To put this more into context, I have a function which handles the HTML rendering of an array of objects, and I want that function to be called automatically every time the array is modified.

1
  • setters are 'helpers' which can parse the variable to be set first. Not sure what possibilities and what level of control you have over your code, but in the setter you can call the function. Commented Mar 12, 2011 at 12:40

7 Answers 7

8

Update

Since Object.watch has been deprecated (since 2018), you should have a look at using a Proxy to allow control over when something is getting updated. A good implementation can be found at How to create a Deep Proxy (aka Proxy Membrane)?

Original answer

Use object.watchdocs and if it is not supported natively look at this implementation: Object.watch() for all browsers?

Sign up to request clarification or add additional context in comments.

1 Comment

6

I don't think what you ask is possible.

A solution might be to :

  • encapsulate your data into a specific object
  • access that data using a setter method of that object
  • have that setter method both :
    • set the data
    • call your function

But it'll require you to rewrite a bit of your code.

1 Comment

Thats the easyiest way to do this i think as well. Maybe some frameworks have capabilities like that as well.
3

It is possible now using Proxy object, see the demo in my answer to similar issue here.

It is possible to create Proxy for array, see the snippet below. In your case, just replace the console.log with your DOM modifying methods. Be careful though: adding a value to array modifies the array length which can invoke the proxy multiple times and modifying the array with it's methods like push() can have other side effects to call the Proxy even more. It depends on UA implementation, but at least one Proxy call per modification should be guaranteed.

const ProxyArr = (arr, fn) => new Proxy(arr, {
    get: (arr, key) => arr[key],
    set: (arr, key, val) => fn(arr[key] = val, key, arr) || 1
});


// listen to array changes
let handler = (v, k, a) => console.log(`setting ${v} at ${k} (${a.length} items)`);
let arr = [];
let proxy = ProxyArr(arr, handler);

// test (see the console output)
proxy[0] = "aa";
proxy.push("bb");
console.log(arr);
console.log(proxy);

Comments

2

You could use setInterval to check for its value so many times a second, and save it into a separate variable. You can check each time whether the real variable is different from the other one. In that case, call the function.

It's a dirty trick, though.

3 Comments

+1 it's dirty, as you say. Not at all nice. But with no other options, in the right scenario, it may just work :)
um .. I guess this would work in smaller applications if you really want ugly and potentially buggy code .. for there is still a small window where the variable is a "new" value but the function has not been run, which, I should expect, would create bugs in certain scenarios. This method, all in all, shouldn't be favored, if you couldn't tell, Mr./Ms. casual observer, who may or may not be reading this comment. I'd just recommend making an object like developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… and using getter/setter functions.
@dylnmc.... that's why he said "in the right scenario." Your one of those people that criticize everything people say on this website. Personally, this could be a working solution.
2

In ECMAScript 5 there are getter/setter properties... Read here: http://ejohn.org/blog/ecmascript-5-objects-and-properties/

Non-IE browsers support something similar:

http://robertnyman.com/2009/05/28/getters-and-setters-with-javascript-code-samples-and-demos/

For IE, you'll have to wait for IE9, or use only DOM-bases getters/setters.

Comments

1

Because JavaScript doesn't universally support setter/getter methods yet, I'd recommend you think about how you set your variables. One technique that would work is:

Array.prototype.setMember = function(index,newValue) {
    alert("I will perform some action here");
    this[index] = newValue;
}

var myArray = [1,2,3];
// x[0] = 11; // Don't do this any more
x.setMember(0,11);
alert(x[0]);

I'm personally not a huge fan of adding new methods to base prototypes, but it makes things easier to refactor in the short term.

1 Comment

yes, this is probably easier and better than making an entirely new object if you just need to do this with an Array for instance. Good thinking
0

I personally prefer to not use proxy and instead use EventEmitter. It would work something like this.

import { EventEmitter } from "events";

const testChangeEvent = new EventEmitter();
function changeTest(newVal){
  test = newVal
  testChangeEvent.emit("change")
}
let test = "val" // variable we want to listen for

and now every time we call changeTest() we can detect it and run code with

testChangeEvent.on("change", () => {
  console.log("Code that is being called")
})

I'm 99% sure you can make it look a lot better and a lot more idiot-proof with getters and setters but this should be enough for small projects if your project is a commercial thought look into it please don't mack people debug for hours.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.