Browse files

- change the way bind works on models

  • Loading branch information...
1 parent 592d5d4 commit 74223b85da66505cd4f897b7fc376ab500641698 @rhysbrettbowen committed Mar 16, 2012
Showing with 111 additions and 52 deletions.
  1. +10 −11 README.md
  2. +1 −1 collection.js
  3. +1 −1 control.js
  4. +1 −1 mediator.js
  5. +76 −33 model.js
  6. +1 −1 router.js
  7. +1 −1 store.js
  8. +7 −1 sync/ajax.js
  9. +6 −1 sync/local.js
  10. +7 −1 sync/sync.js
View
21 README.md
@@ -72,22 +72,13 @@ model.meta('name', ['firstName', 'lastName'], function(firstName, lastName) {
model.get('name'); // returns "Brett-Bowen, Rhys"
```
-the real power in a model comes in binding. You can bind keys, or computed keys to functions or attributes. The bind function takes three arguments. The first is the attribute name or an array of attribute names whose changes you want to listen to. The second is a function which will be passed the value of each of the items you are listening to and the model. Alternatively if you want to bind a value on an object you can just pass the reference as such:
-
-```javascript
-var school = {'name':"SHS",'principal':"someone"};
-var principal = new mvc.Model({'name':"someone"});
-// school principal should always be the same as principal name
-principal.bind('name',school['name']);
-```
-
-if you want to bind it between two models, we give you a helper function:
+the real power in a model comes in binding. You can bind keys, or computed keys to functions or attributes. The bind function takes three arguments. The first is the attribute name or an array of attribute names whose changes you want to listen to. The second is a function which will be passed the value of each of the items you are listening to and the model. If you want to bind it between two models, we give you a helper function:
```
// married couple living together
var husband = new mvc.Model({'city':'San Francisco'});
var wife = new mvc.Model({'city':'San Francisco'});
-husband.bind('city',wife.setBinder('city'));
+husband.bind('city', wife.setBinder('city'));
```
The final parameter is the object to bind the function to. So you could do this:
@@ -101,6 +92,10 @@ task.bind(['done','important'], function(done, important) {
}, element);
```
+if you want to listen to any change you can use bindAll and just pass in a function.
+
+The bindAll and bind functions return an id that can be passed to unbind to remove the binding.
+
There are also other functions that can take parameters such as the boolean "silent" to suppress change events. The other functions available on a model are:
- toJson: used to return a json model that can be used by mvc.Sync or other objects. You should generally override this method with your own implementation
- setSync(mvc.Sync): will set the sync used by the object
@@ -210,6 +205,10 @@ you can then register your object with the mediator and the messages that you ma
### changelog ###
+#### v0.9 ####
+
+- reworked bind for performance
+
#### v0.8 ####
- lots of fixes
View
2 collection.js
@@ -1,4 +1,4 @@
-// goog.mvc 0.4
+// goog.mvc 0.9
// (c) 2012 Rhys Brett-Bowen, Catch.com
// goog.mvc may be freely distributed under the MIT license.
View
2 control.js
@@ -1,4 +1,4 @@
-// goog.mvc 0.4
+// goog.mvc 0.9
// (c) 2012 Rhys Brett-Bowen, Catch.com
// goog.mvc may be freely distributed under the MIT license.
View
2 mediator.js
@@ -1,4 +1,4 @@
-// goog.mvc 0.7
+// goog.mvc 0.9
// (c) 2012 Rhys Brett-Bowen, Catch.com
// goog.mvc may be freely distributed under the MIT license.
View
109 model.js
@@ -1,4 +1,4 @@
-// goog.mvc 0.6
+// goog.mvc 0.9
// (c) 2012 Rhys Brett-Bowen, Catch.com
// goog.mvc may be freely distributed under the MIT license.
@@ -23,13 +23,21 @@ goog.require('goog.object');
*/
mvc.Model = function(options) {
var defaults = {
- schema: null,
- sync: null,
- attr: []
+ 'schema': null,
+ 'sync': null,
+ 'attr': {}
};
+
+ if(!options)
+ options = {};
+ options.attr = options.attr || {};
+
+ goog.object.forEach(options, function(val, key) {
+ if(!goog.isDef(defaults[key]))
+ defaults.attr[key] = val;
+ });
- if(options)
- goog.object.extend(defaults, options);
+ goog.object.extend(defaults, options);
/**
* @private
@@ -54,6 +62,12 @@ mvc.Model = function(options) {
this.sync_ = defaults.sync|| null;
+ this.bound_ = [];
+ this.boundAll_ = {};
+
+ this.changeHandler_ = goog.events.listen(this,
+ goog.events.EventType.CHANGE, this.change_, false, this);
+
this.cid_ = goog.getUid(this);
goog.object.forEach(defaults.attr, function(val, name) {
@@ -231,10 +245,6 @@ mvc.Model.prototype.prev = function(key) {
return goog.object.get(this.prev_, key, null);
};
-mvc.Model.prototype.change = function() {
- this.dispatchEvent(goog.events.EventType.CHANGE);
-};
-
/**
* returns object of changed attributes and their values
*/
@@ -316,8 +326,27 @@ mvc.Model.prototype.getBinder = function(key) {
return goog.bind(this.set, this, key);
};
+mvc.Model.prototype.change_ = function(e) {
+ var changes = this.getChanges();
+ goog.object.forEach(this.bound_, function(val, key) {
+ if(goog.array.some(val.attr, function(attr) {
+ return !!changes[attr];
+ })) {
+ val.fn.apply(val.hn, goog.array.concat(goog.array.map(val.attr,
+ function(attr) {
+ return this.get(attr);
+ }),[this]));
+ }
+ }, this);
+ goog.object.forEach(this.boundAll_, function(val) {
+ val(this);
+ }, this);
+};
+
+
+
/**
- * Allows easy binding of a model's attributre to an element or a function.
+ * Allows easy binding of a model's attribute to an element or a function.
* bind('name', Element(s)) would change the value to the model's name
* bind('name', Element(s), function(El, attr)) runs a function with the element
* and the attributes value
@@ -326,29 +355,43 @@ mvc.Model.prototype.getBinder = function(key) {
* if no name is passed (null or undefined) then the operation will be run on
* any change to the model and pass in the model
*
- * @param {?string} name
- * @param {Function|*} el
- * @param {Function|*=} fn
+ * @param {Array|string} name
+ * @param {Function} fn
+ * @param {*=} opt_handler
*/
-mvc.Model.prototype.bind = function(name, el, fn) {
- goog.events.listen(this, goog.events.EventType.CHANGE, function(e) {
- var changes = e.target.getChanges();
- if(name in changes || !goog.isDefAndNotNull(name)) {
- if(goog.isFunction(el)) {
- goog.bind(el, /** @type {Function} */(fn))(changes[name], this);
- return;
- }
- if(!goog.isArrayLike(el))
- el = [el];
- goog.array.forEach(/** @type {Array} */(el), function(elem) {
- if(goog.isFunction(fn)) {
- fn(elem, changes[name] || this);
- } else {
- elem = changes[name] || this;
- }
- }, this);
- }
- }, false, this);
+mvc.Model.prototype.bind = function(name, fn, opt_handler) {
+ if(goog.isString(name))
+ name = [name];
+ var bind = {
+ attr: name,
+ fn: fn,
+ hn: (opt_handler || this)
+ };
+ bind.cid = goog.getUid(bind);
+ this.bound_.push(bind);
+ return bind.cid;
+};
+
+/**
+ * unbind a listener by id
+ */
+mvc.Model.prototype.unbind = function(id) {
+ return goog.array.removeIf(this.bound_, function(bound) {
+ return (bound.id == id);
+ }) || goog.object.remove(this.boundAll_, id);
+};
+
+/**
+ * bind to any change event
+ *
+ * @param {Function} fn
+ * @param {Object=} opt_handler
+ */
+mvc.Model.prototype.bindAll = function(fn, opt_handler) {
+ var bound = goog.bind(fn, (opt_handler || this));
+ var id = goog.getUid(bound);
+ goog.object.set(this.boundAll_, ""+id, bound);
+ return id;
};
/**
View
2 router.js
@@ -1,4 +1,4 @@
-// goog.mvc 0.4
+// goog.mvc 0.9
// (c) 2012 Rhys Brett-Bowen, Catch.com
// goog.mvc may be freely distributed under the MIT license.
View
2 store.js
@@ -1,4 +1,4 @@
-// goog.mvc 0.6
+// goog.mvc 0.9
// (c) 2012 Rhys Brett-Bowen, Catch.com
// goog.mvc may be freely distributed under the MIT license.
View
8 sync/ajax.js
@@ -1,4 +1,10 @@
-// v0.2
+// goog.mvc v0.9
+
+// (c) 2012 Rhys Brett-Bowen, Catch.com
+// goog.mvc may be freely distributed under the MIT license.
+// For all details and documentation:
+// https://github.com/rhysbrettbowen/goog.mvc
+
goog.provide('mvc.AjaxSync');
goog.require('mvc.Sync');
View
7 sync/local.js
@@ -1,4 +1,9 @@
-// v0.3
+// goog.mvc v0.3
+
+// (c) 2012 Rhys Brett-Bowen, Catch.com
+// goog.mvc may be freely distributed under the MIT license.
+// For all details and documentation:
+// https://github.com/rhysbrettbowen/goog.mvc
goog.provide('mvc.LocalSync');
goog.require('goog.storage.Storage');
View
8 sync/sync.js
@@ -1,4 +1,10 @@
-// v0.1
+// goog.mvc v0.9
+
+// (c) 2012 Rhys Brett-Bowen, Catch.com
+// goog.mvc may be freely distributed under the MIT license.
+// For all details and documentation:
+// https://github.com/rhysbrettbowen/goog.mvc
+
goog.provide('mvc.Sync');

0 comments on commit 74223b8

Please sign in to comment.