From c081c09e989d47da514b7f556436c0d0ddecb530 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 28 Jun 2018 11:09:30 -0400 Subject: [PATCH] [BUGFIX] Setting ArrayProxy#content in willDestroy resets length. Prior to this change, `ArrayProxy.prototype.length` was marked as dirty (and therefore recomputed) when `content` was set due to `arrangedContent` being an alias of `content`, and `ArrayProxy` implementing `PROPERTY_DID_CHANGE` to trap `arrangedContent` changes. Unfortunately, `notifyPropertyChange` avoids notifying _some_ things when the object is destroying. This results in the preexisting `PROPERTY_DID_CHANGE` trap for `arrangedContent` is no longer called, and therefore `length` is never marked as dirty. This fixes the condition, by implementing a `content` trap in `PROPERTY_DID_CHANGE` that marks length as dirty. The next time that `length` is accessed it will do the normal work to recalculate. --- .../ember-runtime/lib/system/array_proxy.js | 3 +++ .../tests/system/array_proxy/length_test.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/ember-runtime/lib/system/array_proxy.js b/packages/ember-runtime/lib/system/array_proxy.js index 67adb343476..b4bcf8a60fe 100644 --- a/packages/ember-runtime/lib/system/array_proxy.js +++ b/packages/ember-runtime/lib/system/array_proxy.js @@ -230,6 +230,9 @@ export default class ArrayProxy extends EmberObject { this.arrayContentDidChange(0, oldLength, newLength); this._addArrangedContentArrayObsever(); + } else if (key === 'content') { + this._objectsDirtyIndex = 0; + this._lengthDirty = true; } } diff --git a/packages/ember-runtime/tests/system/array_proxy/length_test.js b/packages/ember-runtime/tests/system/array_proxy/length_test.js index 00c4b1b0368..2ab0d106bfa 100644 --- a/packages/ember-runtime/tests/system/array_proxy/length_test.js +++ b/packages/ember-runtime/tests/system/array_proxy/length_test.js @@ -78,6 +78,24 @@ moduleFor( assert.deepEqual(obj.content, null, 'content was updated'); } + '@test accessing length after content set to null in willDestroy'(assert) { + let obj = ArrayProxy.extend({ + willDestroy() { + this.set('content', null); + this._super(...arguments); + }, + }).create({ + content: ['foo', 'bar'], + }); + + assert.equal(obj.length, 2, 'precond'); + + this.runTask(() => obj.destroy()); + + assert.equal(obj.length, 0, 'length is 0 without content'); + assert.deepEqual(obj.content, null, 'content was updated'); + } + '@test setting length to 0'(assert) { let obj = ArrayProxy.create({ content: ['foo', 'bar'] });