Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if an object variable has been changed?

Tags:

javascript

I have a class that represents a fence, internally its made up from rectangle and circle marker objects (also my classes). The fence has 4 variables - x1, x2, y1 and y2. If any of these changes I have to modify or rebuild the internal marker objects.

Storing and checking the 4 values isn't such a big deal but this is just the first of my world object classes and there will be ones with much longer lists of variables. Is there any good way of checking whether any of these has changed or trigger something on change without explicitly storing double values and checking each time the canvas is redrawn? Something like a property in vb.net or such?

like image 716
Jake Freelander Avatar asked Jul 14 '14 20:07

Jake Freelander


People also ask

How can I check if object obj has property prop?

The hasOwnProperty() method will check if an object contains a direct property and will return true or false if it exists or not. The hasOwnProperty() method will only return true for direct properties and not inherited properties from the prototype chain.

How do you check if an object has the same value in JavaScript?

The Object.is() method determines whether two values are the same value.

How do you know if an object has a key and value?

You can use the JavaScript in operator to check if a specified property/key exists in an object. It has a straightforward syntax and returns true if the specified property/key exists in the specified object or its prototype chain. Note: The value before the in keyword should be of type string or symbol .


2 Answers

var fence= {
   set x1(){
      alert('change');
      this.rebuild();
   },
   rebuild: function(){}
}

Also

function Fence(val){
    var value = val;

    this.__defineGetter__("x1", function(){
        return value;
    });

    this.__defineSetter__("x1", function(val){
        alert('change');
        this.rebuild();
    });
    this.rebuild = function(){};
}
var fence = new Fence();
like image 51
KJ Price Avatar answered Oct 02 '22 15:10

KJ Price


Using the object posted in the code below, you can achieve it quite easily:

function Fence() {
    // constructor
}

Fence.prototype.refresh = function() {
    // change the refresh code here
    console.log(this.x1 + "," + this.y1 + "," + this.x2 + "," + this.y2);
};

// must be called after the prototype.refresh function is defined
RefreshExtender.addRefreshProperties(Fence, [
        new RefreshExtender.Property("x1", 0), // propertyName, defaultValue[, refreshFunction]
        new RefreshExtender.Property("y1", 0, function() { console.log('Refresh only y1 property.'); }),
        new RefreshExtender.Property("x2", 0),
        new RefreshExtender.Property("y2", 0)
    ]);

Then when using it:

var fence = new Fence();
fence.x1 = 20;
// Outputs: "20,0,0,0"

Now if you change multiple properties at once, it will only call the refresh function after all the properties have been set. For example:

fence.x1 = 10; 
fence.x2 = 20;
// Outputs: "10,0,20,0 (Outputs only ONCE)"

If we update the y1 property, it will execute the function passed in when creating the property:

fence.y1 = 30;
// Outputs: "Refresh only y1 property."

Refresh Extender:

var RefreshExtender = {
    addRefreshProperties: function(baseType, properties) {
        function defineProperty(property) {
            Object.defineProperty(baseType.prototype, property.name, {
                get: function() {
                    var val = this["_" + property.name];
                    if (typeof val === "undefined") {
                        return property.defaultValue;
                    }
                    return val;
                },
                set: function(val) {
                    var shouldRefresh = this["_" + property.name] !== val;
                    this["_" + property.name] = val;
                    if (shouldRefresh) {
                        if (typeof property.refreshFunction === "function") {
                            property.refreshFunction();
                        }
                        else {
                            this.refresh();
                        }
                    }
                },
                enumerable: true,
                configurable: true
            });
        }

        for (var i = 0, l = properties.length; i < l; i++) {
            defineProperty(properties[i]);
        }

        var oldRefreshFunction = baseType.prototype.refresh;

        baseType.prototype.refresh = RefreshExtender._executeOnce(oldRefreshFunction);
    },
    Property : function(name, defaultValue, refreshFunction) {
        this.name            = name;
        this.defaultValue    = defaultValue;
        if (typeof refreshFunction === "function") {
            this.refreshFunction = RefreshExtender._executeOnce(refreshFunction);
        }
    },
    _executeOnce : function(originalFunc) {
        var isRefreshing = false,
            func = function() {
                var _this = this;
                if (!isRefreshing) {
                    isRefreshing = true;
                    setTimeout(function() {
                        isRefreshing = false;
                        originalFunc.call(_this);
                    }, 0);
                }
            };

        return func;
    }
};
like image 25
David Sherret Avatar answered Oct 02 '22 15:10

David Sherret