From 15899a035e3bcf4b883b6f227a8ae0e902635fa9 Mon Sep 17 00:00:00 2001 From: tchak Date: Sat, 18 Jul 2015 10:40:45 +0200 Subject: [PATCH] [BUGFIX release] fix array observers and property notifications Closes #3498 --- .../ember-data/lib/system/model/errors.js | 39 ++++++++++--------- .../unit/model/rollback-attributes-test.js | 20 ++++++++++ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/packages/ember-data/lib/system/model/errors.js b/packages/ember-data/lib/system/model/errors.js index 1536d72f778..df2ea3a04a8 100644 --- a/packages/ember-data/lib/system/model/errors.js +++ b/packages/ember-data/lib/system/model/errors.js @@ -1,5 +1,7 @@ var get = Ember.get; +var set = Ember.set; var isEmpty = Ember.isEmpty; +var makeArray = Ember.makeArray; import { MapWithDefault @@ -91,7 +93,7 @@ import { @uses Ember.Enumerable @uses Ember.Evented */ -export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { +export default Ember.ArrayProxy.extend(Ember.Evented, { /** Register with target handler @@ -176,14 +178,6 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { return errors; }, - /** - @method nextObject - @private - */ - nextObject: function(index, previousObject, context) { - return get(this, 'content').objectAt(index); - }, - /** Total number of errors. @@ -191,7 +185,6 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { @type {Number} @readOnly */ - length: Ember.computed.oneWay('content.length').readOnly(), /** @property isEmpty @@ -220,11 +213,10 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { var wasEmpty = get(this, 'isEmpty'); messages = this._findOrCreateMessages(attribute, messages); - get(this, 'content').addObjects(messages); + this.addObjects(messages); get(this, 'errorsByAttributeName').get(attribute).addObjects(messages); this.notifyPropertyChange(attribute); - this.enumerableContentDidChange(); if (wasEmpty && !get(this, 'isEmpty')) { this.trigger('becameInvalid'); @@ -238,7 +230,7 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { _findOrCreateMessages: function(attribute, messages) { var errors = this.errorsFor(attribute); - return Ember.makeArray(messages).map((message) => { + return makeArray(messages).map((message) => { return errors.findBy('message', message) || { attribute: attribute, message: message @@ -283,12 +275,11 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { remove: function(attribute) { if (get(this, 'isEmpty')) { return; } - var content = get(this, 'content').rejectBy('attribute', attribute); - get(this, 'content').setObjects(content); + let content = this.rejectBy('attribute', attribute); + set(this, 'content', content); get(this, 'errorsByAttributeName').delete(attribute); this.notifyPropertyChange(attribute); - this.enumerableContentDidChange(); if (get(this, 'isEmpty')) { this.trigger('becameValid'); @@ -319,9 +310,19 @@ export default Ember.Object.extend(Ember.Enumerable, Ember.Evented, { clear: function() { if (get(this, 'isEmpty')) { return; } - get(this, 'content').clear(); - get(this, 'errorsByAttributeName').clear(); - this.enumerableContentDidChange(); + let errorsByAttributeName = get(this, 'errorsByAttributeName'); + let attributes = Ember.A(); + + errorsByAttributeName.forEach(function(_, attribute) { + attributes.push(attribute); + }); + + errorsByAttributeName.clear(); + attributes.forEach(function(attribute) { + this.notifyPropertyChange(attribute); + }, this); + + this._super(); this.trigger('becameValid'); }, diff --git a/packages/ember-data/tests/unit/model/rollback-attributes-test.js b/packages/ember-data/tests/unit/model/rollback-attributes-test.js index b5f5445f984..7a35e52867b 100644 --- a/packages/ember-data/tests/unit/model/rollback-attributes-test.js +++ b/packages/ember-data/tests/unit/model/rollback-attributes-test.js @@ -228,6 +228,7 @@ test("deleted record's attributes can be rollbacked", function() { }); test("invalid record's attributes can be rollbacked", function() { + expect(10); Dog = DS.Model.extend({ name: DS.attr() }); @@ -263,17 +264,32 @@ test("invalid record's attributes can be rollbacked", function() { }); run(function() { + Ember.addObserver(dog, 'errors.name', function() { + ok(true, 'errors.name did change'); + }); + + dog.get('errors').addArrayObserver({}, { + willChange: function() { + ok(true, 'errors will change'); + }, + didChange: function() { + ok(true, 'errors did change'); + } + }); + dog.save().then(null, async(function() { dog.rollbackAttributes(); equal(dog.get('hasDirtyAttributes'), false, "must not be dirty"); equal(dog.get('name'), "Pluto"); + ok(Ember.isEmpty(dog.get('errors.name'))); ok(dog.get('isValid')); })); }); }); test("invalid record's attributes rolled back to correct state after set", function() { + expect(13); Dog = DS.Model.extend({ name: DS.attr(), breed: DS.attr() @@ -311,6 +327,10 @@ test("invalid record's attributes rolled back to correct state after set", funct }); run(function() { + Ember.addObserver(dog, 'errors.name', function() { + ok(true, 'errors.name did change'); + }); + dog.save().then(null, async(function() { equal(dog.get('name'), "is a dwarf planet"); equal(dog.get('breed'), "planet");