Reputation: 23645
i have an array of objects, and these objects all have an 'isvalid' attribute.
Is there a way with JQuery or plain javascript to bind code to the event that the value of that property changes?
So when i have an array with 10 objects, i want to execute a function when the 'isvalid' property of one of the object changes.
Is that possible?
Michel
Upvotes: 3
Views: 1911
Reputation: 1075159
It's possible with plain JavaScript by using a property setter function. Using ES5 syntax, that looks like this (live example -- works in Chrome and other browsers with reasonable ES5-compliance):
// Our constructor function
function Thing() {
}
// Define a "foo" property with a setter and getter
Object.defineProperty(Thing.prototype, "foo", {
set: function(value) {
this.fooStorage = value;
display("Foo was set to '" + value + "'");
},
get: function() {
return this.fooStorage;
}
});
// Create a `Thing`
var t = new Thing();
// Set its property
t.foo = "bar";
When the t.foo = "bar";
assignment is executed, the setter function is called. You can have the setter function call a callback if you like, to notify you that the Thing
object was changed.
Note that the above is just an example. It uses the fooStorage
property to store the value of foo
, which is less than ideal but nice and simple for an example.
To do this in a way that's compatible with non-ES5 JavaScript engines, you either have to fall back on some proprietary and now-deprecated syntax from Mozilla (which won't work on other engines), or just use an explicit setter function (live example):
// Our constructor function
function Thing() {
}
// Define a "foo" property with a setter and getter
Thing.prototype.setFoo = function(value) {
this.fooStorage = value;
display("Foo was set to '" + value + "'");
};
Thing.prototype.getFoo = function() {
return this.fooStorage;
};
// Create a `Thing`
var t = new Thing();
// Set the property
t.setFoo("bar");
(And again, this is just an example using a simplistic means of storing foo
's value.)
This has the advantage that it works with just about any JavaScript engine, not just ES5-compliant ones, and it's explicit that setting foo
is a function call, not just a property assignment (whereas with the ES5 setter/getter syntax, the person setting the foo
property doesn't know that it's a function call — which has upsides and downsides).
So that's how you capture the fact that the property changed. Then it's just a matter of allowing callbacks to be registered and removed to receive notification of changes. These are easily managed in a simple array. Here's an ES5-based example doing it on a per-object basis; obviously you could do this in some kind of grouped way instead for the entire array of objects you want to let people watch. (live copy)
window.onload = function() {
// Our constructor function
function Thing() {
this.fooHandlers = [];
}
// Add a listener for "foo" changes
Thing.prototype.addFooChangeHandler = function(callback) {
this.fooHandlers.push(callback);
};
// Remove a listener for "foo" changes
Thing.prototype.removeFooChangeHandler = function(callback) {
var index;
index = this.fooHandlers.indexOf(callback);
if (index >= 0) {
this.fooHandlers.splice(index, 1);
}
};
// Define a "foo" property with a setter and getter
Object.defineProperty(Thing.prototype, "foo", {
set: function(value) {
var index;
for (index = 0; index < this.fooHandlers.length; ++index) {
try {
// Handler receives a reference to this Thing,
// foo's old value, and foo's new value.
this.fooHandlers[index](this, value, this.fooStorage);
}
catch (e) {
}
}
this.fooStorage = value;
},
get: function() {
return this.fooStorage;
}
});
// Create a `Thing`
var t = new Thing();
// Add a foo change handler
t.addFooChangeHandler(function(t, newValue, oldValue) {
display("Handler 1: Foo changed from '" + oldValue + "' to '" + newValue + "'");
});
// Add another
t.addFooChangeHandler(function(t, newValue, oldValue) {
display("Handler 2: Foo changed from '" + oldValue + "' to '" + newValue + "'");
});
// Set the property
t.foo = "bar";
t.foo = "boo";
// === Basic utility functions
function display(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.body.appendChild(p);
}
};
To do that without an ES5 JavaScript engine, just set the setFoo
/ getFoo
model described earlier, and make sure the engine supports Array#indexOf
correctly (some engines don't have it at all, some use ==
rather than ===
equivalence) or replace the use of Array#indexOf
in removeFooChangeHandler
with a simple loop through the array looking for the callback:
// Remove a listener for "foo" changes
Thing.prototype.removeFooChangeHandler = function(callback) {
var index;
for (index = 0; index < this.fooHandlers.length; ++index) {
if (this.fooHandlers[index] === callback) {
this.fooHandlers.splice(index, 1);
break;
}
}
};
Side note: There are a number of anonymous functions in these examples. I've done that to avoid making things seem complex, but I'm not a fan of anonymous functions, I prefer that functions have names. See the link for details.
Upvotes: 4
Reputation: 19217
Take a look at this: http://blog.hydroprofessional.com/?p=84
This is get you notified when you property changes
Upvotes: 0
Reputation: 76890
One thing you could do is set the property of the object as private and then change them only with a setter. This way you could trigger an event each time you set the variable with the setter. this would work in any environment.
If you ar limited to the browser you could use watch (give a look here Object.watch() for all browsers? for compatibilty between browsers)
Upvotes: 0