Search code examples
javascriptlistenerprototypeinterceptorsetter

Intercept javascript value setter


How can I listen to value set on a variable or object property without losing other listeners.

for example

var myModel;
myModel = 10;
var myListener1 = function(oldVal, newVal) {
    //do stuff
}
var myListener2 = function(oldVal, newVal) {
    //do other stuff
}

here I want myListener1 and myListener2 to be called whenever a value is set for variable myModel. Later in other functions might also want to add another listener to myModel on setter so it shouldn't override existing ones.

I know there should be a way to do it with Object.defineProperty(). Also it would be good to have a solution cross browser for IE8+.


Solution

  • For the following method, you would have to use an object with a property, but it works.


    // this is very similar to using Object.watch()
    // instead we attach multiple listeners
    var myModel = (function () {
        var actualValue,
            interceptors = [];
    
        function callInterceptors(newValue) {
            for (var i = 0; i < interceptors.length; i += 1) {
                interceptors[i](newValue);
            }
        }
    
        return {
            get value() {
                // user never has access to the private variable "actualValue"
                // we can control what they get back from saying "myModel.value"
                return actualValue;
            },
    
            set value(newValue) {
                callInterceptors(newValue);
                actualValue = newValue;
            },
    
            listen : function (fn) {
                if (typeof fn === 'function') {
                    interceptors.push(fn);
                }
            }
        };
    }());
    
    // add a listener
    myModel.listen(function (passedValue) {
        alert('You tried to set myValue to ' + passedValue);
    });
    
    // add another listener
    myModel.listen(function (passedValue) {
        alert('AAARRG! Why did you modify that value to ' + passedValue + '?!?!');
    });
    
    // our functions are called when we
    // modify our value
    myModel.value = 10;


    jsFiddle example