Skip to content

Instantly share code, notes, and snippets.

@jsocol
Created May 3, 2012 19:49
Show Gist options
  • Select an option

  • Save jsocol/2588776 to your computer and use it in GitHub Desktop.

Select an option

Save jsocol/2588776 to your computer and use it in GitHub Desktop.
EventArray.js - Arrays you can watch.
/**
* EventArray.js - Arrays you can watch.
* Copyright 2012, James Socol <me@jamessocol.com>
*
* Released under the MIT X11 and BSD 2-clause Licenses.
*
* EventArray.js is a simple wrapper around JS arrays that makes it
* easier to use them for data-driven UIs by providing a way to watch
* them for mutations. Think of the lovechild of an Array and an
* EventEmitter.
*
* var arr = new EventArray();
* arr.on('push', function(newElement) {
* console.log("you added:", newElement);
* console.log("the array is now this long:", this.length);
* });
* arr.push('foo');
* >>> you added: foo
* >>> the array is now this long: 1
*
* All the mutator methods emit events you can listen to, for example,
* calling `(new EventArray()).push(1)` emits 'push' event.
*
* Depending on the event, registered callbacks will receive different
* arguments. All callbacks have access to the EventArray itself as the
* 'this' object.
*
* Events, with arguments:
* 'change' - no arguments - fired on any mutation.
* 'push' - the element pushed - if multiple values are pushed, multiple
* push events will be fired.
* 'pop' - the element popped.
* '... these docs need to live elsewhere.
*/
function EventArray() {
this.callbacks = {
'change': [],
'push': [],
'pop': [],
'shift': [],
'unshift': [],
'sort': [],
'reverse': [],
'splice': []
};
return this;
}
EventArray.prototype = Object.create(Array.prototype);
EventArray.prototype.emit = function (type) {
var args = Array.prototype.slice.call(arguments, 1),
self = this;
if (type in this.callbacks) {
this.callbacks[type].forEach(function(fn) {
fn.apply(self, args);
}, self);
}
return this;
};
EventArray.prototype.on = function (type, callback) {
if (!(type in this.callbacks)) {
this.callbacks[type] = [callback];
} else {
this.callbacks[type].push(callback);
}
return this;
};
EventArray.prototype.push = function () {
var self = this;
Array.prototype.forEach.call(arguments, function(el) {
Array.prototype.push.call(self, el);
self.emit('push', el);
});
this.emit('change');
return this.length;
};
EventArray.prototype.pop = function() {
var el = Array.prototype.pop.call(this);
this.emit('pop', el);
this.emit('change');
return el;
};
EventArray.prototype.shift = function() {
var el = Array.prototype.shift.call(this);
this.emit('shift', el);
this.emit('change');
return el;
};
EventArray.prototype.unshift = function() {
var self = this;
// Unshift adds in the order of the arguments, so we need to reverse them
// to add one at a time.
Array.prototype.reverse.call(arguments);
Array.prototype.forEach.call(arguments, function(el) {
Array.prototype.unshift.call(self, el);
self.emit('unshift', el);
});
this.emit('change');
return this.length;
};
EventArray.prototype.sort = function(cmp) {
Array.prototype.sort.call(this, cmp);
this.emit('sort');
this.emit('change');
return this;
};
EventArray.prototype.reverse = function() {
Array.prototype.reverse.call(this);
this.emit('reverse');
this.emit('change');
return this;
};
EventArray.prototype.splice = function() {
var removed = Array.prototype.splice.apply(this, arguments);
this.emit('splice', removed);
this.emit('change');
return removed;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment