diff --git a/README.md b/README.md index bdc6a08..9d6a455 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Example code: { name: 'Cyrril' } ] }); - + //You can bind to change events on nested attributes model.bind('change:user.name.first', function(model, val) { console.log(val); @@ -48,14 +48,14 @@ Example code: //Wildcards are supported model.bind('change:user.*', function() {}); - + //Use set with a path name for nested attributes //NOTE you must you quotation marks around the key name when using a path model.set({ 'user.name.first': 'Lana', 'user.name.last': 'Kang' }); - + //Use get() with path names so you can create getters later console.log(model.get('user.type')); // 'Spy' @@ -78,6 +78,9 @@ Contributors Changelog ========= +0.10.5: +- Trigger change events only once and trigger change event for parent keys (like wildcard) + 0.10.4: - Fix #68 Model or collection in attributes are eliminated when defaults are used diff --git a/distribution/deep-model.js b/distribution/deep-model.js index 5307ffc..9ddd6a0 100644 --- a/distribution/deep-model.js +++ b/distribution/deep-model.js @@ -1,7 +1,7 @@ /*jshint expr:true eqnull:true */ /** * - * Backbone.DeepModel v0.10.4 + * Backbone.DeepModel v0.10.5 * * Copyright (c) 2013 Charles Davison, Pow Media Ltd * @@ -132,7 +132,7 @@ factory(_, Backbone); } }(function(_, Backbone) { - + /** * Takes a nested object and returns a shallow object keyed with the path names * e.g. { "level1.level2": "value" } @@ -184,7 +184,7 @@ if (result == null && i < n - 1) { result = {}; } - + if (typeof result === 'undefined') { if (return_exists) { @@ -274,7 +274,7 @@ set: function(key, val, options) { var attr, attrs, unset, changes, silent, changing, prev, current; if (key == null) return this; - + // Handle both `"key", value` and `{key: value}` -style arguments. if (typeof key === 'object') { attrs = key; @@ -284,7 +284,7 @@ } options || (options = {}); - + // Run validation. if (!this._validate(attrs, options)) return false; @@ -329,11 +329,15 @@ // var separator = DeepModel.keyPathSeparator; + var alreadyTriggered = {}; // * @restorer for (var i = 0, l = changes.length; i < l; i++) { var key = changes[i]; - this.trigger('change:' + key, this, getNested(current, key), options); + if (!alreadyTriggered.hasOwnProperty(key) || !alreadyTriggered[key]) { // * @restorer + alreadyTriggered[key] = true; // * @restorer + this.trigger('change:' + key, this, getNested(current, key), options); + } // * @restorer var fields = key.split(separator); @@ -342,7 +346,17 @@ var parentKey = _.first(fields, n).join(separator), wildcardKey = parentKey + separator + '*'; - this.trigger('change:' + wildcardKey, this, getNested(current, parentKey), options); + if (!alreadyTriggered.hasOwnProperty(wildcardKey) || !alreadyTriggered[wildcardKey]) { // * @restorer + alreadyTriggered[wildcardKey] = true; // * @restorer + this.trigger('change:' + wildcardKey, this, getNested(current, parentKey), options); + } // * @restorer + + // + @restorer + if (!alreadyTriggered.hasOwnProperty(parentKey) || !alreadyTriggered[parentKey]) { + alreadyTriggered[parentKey] = true; + this.trigger('change:' + parentKey, this, getNested(current, parentKey), options); + } + // - @restorer } // } @@ -388,7 +402,7 @@ // var old = this._changing ? this._previousAttributes : this.attributes; - + // diff = objToPaths(diff); old = objToPaths(old); @@ -431,7 +445,7 @@ //For use in NodeJS if (typeof module != 'undefined') module.exports = DeepModel; - + return Backbone; })); diff --git a/distribution/deep-model.min.js b/distribution/deep-model.min.js index e488ad5..92c149b 100644 --- a/distribution/deep-model.min.js +++ b/distribution/deep-model.min.js @@ -1,7 +1,7 @@ /*jshint expr:true eqnull:true */ /** * - * Backbone.DeepModel v0.10.4 + * Backbone.DeepModel v0.10.5 * * Copyright (c) 2013 Charles Davison, Pow Media Ltd * @@ -9,4 +9,4 @@ * Licensed under the MIT License */ -(function(){var e,t,n,r,i,s,o=[].slice;n=function(e){var t,r;return!_.isObject(e)||_.isFunction(e)?e:e instanceof Backbone.Collection||e instanceof Backbone.Model?e:_.isDate(e)?new Date(e.getTime()):_.isRegExp(e)?new RegExp(e.source,e.toString().replace(/.*\//,"")):(r=_.isArray(e||_.isArguments(e)),t=function(e,t,i){return r?e.push(n(t)):e[i]=n(t),e},_.reduce(e,t,r?[]:{}))},s=function(e){return e==null?!1:(e.prototype==={}.prototype||e.prototype===Object.prototype)&&_.isObject(e)&&!_.isArray(e)&&!_.isFunction(e)&&!_.isDate(e)&&!_.isRegExp(e)&&!_.isArguments(e)},t=function(e){return _.filter(_.keys(e),function(t){return s(e[t])})},e=function(e){return _.filter(_.keys(e),function(t){return _.isArray(e[t])})},i=function(n,r,s){var o,u,a,f,l,c,h,p,d,v;s==null&&(s=20);if(s<=0)return console.warn("_.deepExtend(): Maximum depth of recursion hit."),_.extend(n,r);c=_.intersection(t(n),t(r)),u=function(e){return r[e]=i(n[e],r[e],s-1)};for(h=0,d=c.length;h0)e=i(e,n(r.shift()),t);return e},_.mixin({deepClone:n,isBasicObject:s,basicObjects:t,arrays:e,deepExtend:r})}).call(this),function(e){typeof define=="function"&&define.amd?define(["underscore","backbone"],e):e(_,Backbone)}(function(e,t){function n(t){var r={},i=o.keyPathSeparator;for(var s in t){var u=t[s];if(u&&u.constructor===Object&&!e.isEmpty(u)){var a=n(u);for(var f in a){var l=a[f];r[s+i+f]=l}}else r[s]=u}return r}function r(t,n,r){var i=o.keyPathSeparator,s=n.split(i),u=t;r||r===!1;for(var a=0,f=s.length;a0;E--){var S=e.first(w,E).join(g),x=S+g+"*";this.trigger("change:"+x,this,r(m,S),a)}}}if(d)return this;if(!p)while(this._pending)this._pending=!1,this.trigger("change",this,a);return this._pending=!1,this._changing=!1,this},clear:function(t){var r={},i=n(this.attributes);for(var s in i)r[s]=void 0;return this.set(r,e.extend({},t,{unset:!0}))},hasChanged:function(t){return t==null?!e.isEmpty(this.changed):r(this.changed,t)!==undefined},changedAttributes:function(t){if(!t)return this.hasChanged()?n(this.changed):!1;var r=this._changing?this._previousAttributes:this.attributes;t=n(t),r=n(r);var i,s=!1;for(var o in t){if(e.isEqual(r[o],i=t[o]))continue;(s||(s={}))[o]=i}return s},previous:function(e){return e==null||!this._previousAttributes?null:r(this._previousAttributes,e)},previousAttributes:function(){return e.deepClone(this._previousAttributes)}});return o.keyPathSeparator=".",t.DeepModel=o,typeof module!="undefined"&&(module.exports=o),t}) +(function(){var e,t,n,r,i,s,o=[].slice;n=function(e){var t,r;return!_.isObject(e)||_.isFunction(e)?e:e instanceof Backbone.Collection||e instanceof Backbone.Model?e:_.isDate(e)?new Date(e.getTime()):_.isRegExp(e)?new RegExp(e.source,e.toString().replace(/.*\//,"")):(r=_.isArray(e||_.isArguments(e)),t=function(e,t,i){return r?e.push(n(t)):e[i]=n(t),e},_.reduce(e,t,r?[]:{}))},s=function(e){return e==null?!1:(e.prototype==={}.prototype||e.prototype===Object.prototype)&&_.isObject(e)&&!_.isArray(e)&&!_.isFunction(e)&&!_.isDate(e)&&!_.isRegExp(e)&&!_.isArguments(e)},t=function(e){return _.filter(_.keys(e),function(t){return s(e[t])})},e=function(e){return _.filter(_.keys(e),function(t){return _.isArray(e[t])})},i=function(n,r,s){var o,u,a,f,l,c,h,p,d,v;s==null&&(s=20);if(s<=0)return console.warn("_.deepExtend(): Maximum depth of recursion hit."),_.extend(n,r);c=_.intersection(t(n),t(r)),u=function(e){return r[e]=i(n[e],r[e],s-1)};for(h=0,d=c.length;h0)e=i(e,n(r.shift()),t);return e},_.mixin({deepClone:n,isBasicObject:s,basicObjects:t,arrays:e,deepExtend:r})}).call(this),function(e){typeof define=="function"&&define.amd?define(["underscore","backbone"],e):e(_,Backbone)}(function(e,t){function n(t){var r={},i=o.keyPathSeparator;for(var s in t){var u=t[s];if(u&&u.constructor===Object&&!e.isEmpty(u)){var a=n(u);for(var f in a){var l=a[f];r[s+i+f]=l}}else r[s]=u}return r}function r(t,n,r){var i=o.keyPathSeparator,s=n.split(i),u=t;r||r===!1;for(var a=0,f=s.length;a0;S--){var x=e.first(E,S).join(g),T=x+g+"*";if(!y.hasOwnProperty(T)||!y[T])y[T]=!0,this.trigger("change:"+T,this,r(m,x),a);if(!y.hasOwnProperty(x)||!y[x])y[x]=!0,this.trigger("change:"+x,this,r(m,x),a)}}}if(d)return this;if(!p)while(this._pending)this._pending=!1,this.trigger("change",this,a);return this._pending=!1,this._changing=!1,this},clear:function(t){var r={},i=n(this.attributes);for(var s in i)r[s]=void 0;return this.set(r,e.extend({},t,{unset:!0}))},hasChanged:function(t){return t==null?!e.isEmpty(this.changed):r(this.changed,t)!==undefined},changedAttributes:function(t){if(!t)return this.hasChanged()?n(this.changed):!1;var r=this._changing?this._previousAttributes:this.attributes;t=n(t),r=n(r);var i,s=!1;for(var o in t){if(e.isEqual(r[o],i=t[o]))continue;(s||(s={}))[o]=i}return s},previous:function(e){return e==null||!this._previousAttributes?null:r(this._previousAttributes,e)},previousAttributes:function(){return e.deepClone(this._previousAttributes)}});return o.keyPathSeparator=".",t.DeepModel=o,typeof module!="undefined"&&(module.exports=o),t}) diff --git a/package.json b/package.json index 5fe2834..ea9c8ee 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "author": { "name": "Charles Davison" }, - "version": "0.10.4", + "version": "0.10.5", "dependencies": { "backbone": ">=0.9.10" },