diff --git a/addon/create-class-computed.js b/addon/create-class-computed.js index c4f726b..a3d28aa 100644 --- a/addon/create-class-computed.js +++ b/addon/create-class-computed.js @@ -100,17 +100,27 @@ export default function(observerBools, macroGenerator) { } let mappedKeys = []; + let originalKeys = []; - function rewriteComputed(obj, key) { - let mappedWithResolvedOberverKeys = mappedKeys.map((macro, i) => { + function createComputed(keys, context, key) { + let resolvedOberverKeys = keys.map((macro, i) => { let shouldObserve = observerBools[i]; if (shouldObserve) { - macro = getValue({ context: this, macro, key }); + // succeeds with `raw`, fails with everything else + try { + macro = getValue({ context, macro, key }); + } catch (err) { + macro = undefined; + } } return macro; }); - let cp = macroGenerator.apply(this, mappedWithResolvedOberverKeys); + return macroGenerator.apply(context, resolvedOberverKeys); + } + + function rewriteComputed(obj, key) { + let cp = createComputed(mappedKeys, this, key); defineProperty(this, 'computed', cp); } @@ -124,6 +134,7 @@ export default function(observerBools, macroGenerator) { let mappedKey = resolveMappedLocation(key, i); + originalKeys.push(key); mappedKeys.push(mappedKey); if (shouldObserve) { classProperties[`key${i}DidChange`] = observer(mappedKey, rewriteComputed); @@ -159,6 +170,11 @@ export default function(observerBools, macroGenerator) { return get(propertyInstance, 'computed'); }).readOnly(); + // workaround for watching array and object rewriting properties + // in class computed scope while composing macros + // ex `first(filterBy('arr', 'prop'))` + cp._classComputed = createComputed(originalKeys); + return cp; }; } diff --git a/addon/flatten-keys.js b/addon/flatten-keys.js index c3c72a0..d3081ba 100644 --- a/addon/flatten-keys.js +++ b/addon/flatten-keys.js @@ -8,6 +8,14 @@ function flattenKey(key, flattenedKeys) { return; } + // workaround for watching array and object rewriting properties + // in class computed scope while composing macros + // ex `first(filterBy('arr', 'prop'))` + let classComputed = key._classComputed; + if (classComputed) { + dependentKeys = classComputed._dependentKeys; + } + return _flattenKeys(dependentKeys, flattenedKeys); } diff --git a/tests/acceptance/application-test.js b/tests/acceptance/application-test.js index 7b8722a..9a33ec3 100644 --- a/tests/acceptance/application-test.js +++ b/tests/acceptance/application-test.js @@ -32,4 +32,14 @@ module('Acceptance | application', function(hooks) { assert.equal(find('.items').textContent, 1); }); + + test('class computed array macro inside a normal array macro, handles pushes', async function(assert) { + await visit('/compose-class-computed'); + + assert.equal(find('.computed').textContent, '1'); + + await click('button'); + + assert.equal(find('.computed').textContent, '3'); + }); }); diff --git a/tests/dummy/app/controllers/compose-class-computed.js b/tests/dummy/app/controllers/compose-class-computed.js new file mode 100644 index 0000000..53fbe76 --- /dev/null +++ b/tests/dummy/app/controllers/compose-class-computed.js @@ -0,0 +1,41 @@ +import Controller from '@ember/controller'; +import EmberObject, { get } from '@ember/object'; +import { A as emberA } from '@ember/array'; +import createClassComputed from 'ember-macro-helpers/create-class-computed'; +import computed from 'ember-macro-helpers/computed'; +import raw from 'ember-macro-helpers/raw'; +import normalizeArrayKey from 'ember-macro-helpers/normalize-array-key'; + +const filterBy = createClassComputed( + [false, true], + (arr, key, val) => computed(normalizeArrayKey(arr, [key]), val, (arr, val) => arr.filterBy(key, val)) +); + +export default Controller.extend({ + array: emberA([ + EmberObject.create({ + testProp: 'test val 1', + testProp2: 1 + }), + EmberObject.create({ + testProp: 'test val 2', + testProp2: 2 + }) + ]), + index: 0, + testProp: 'testProp', + + computed: computed( + filterBy('array', 'testProp', raw('test val 1')), + array => get(array[array.length - 1], 'testProp2') + ), + + actions: { + update() { + get(this, 'array').pushObject(EmberObject.create({ + testProp: 'test val 1', + testProp2: 3 + })); + } + } +}); diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index 7ca0b5e..c99c031 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -9,6 +9,7 @@ const Router = EmberRouter.extend({ Router.map(function() { this.route('double-render'); this.route('no-rerender'); + this.route('compose-class-computed'); }); export default Router; diff --git a/tests/dummy/app/templates/compose-class-computed.hbs b/tests/dummy/app/templates/compose-class-computed.hbs new file mode 100644 index 0000000..c7af736 --- /dev/null +++ b/tests/dummy/app/templates/compose-class-computed.hbs @@ -0,0 +1,3 @@ +
{{computed}}
+ + \ No newline at end of file diff --git a/tests/integration/create-class-computed-test.js b/tests/integration/create-class-computed-test.js index 2a46ea4..e7cf620 100644 --- a/tests/integration/create-class-computed-test.js +++ b/tests/integration/create-class-computed-test.js @@ -21,7 +21,7 @@ module('Integration | create class computed', function(hooks) { filterBy = createClassComputed( [false, true], function(array, key, value) { - if (!key) { + if (!key && this) { PROPERTIES.set(this, array.split('.').reverse()[0]); } return computed(normalizeArrayKey(array, [key]), value, function(array, value) { diff --git a/tests/unit/create-class-computed-test.js b/tests/unit/create-class-computed-test.js index 96dbca7..1b81661 100644 --- a/tests/unit/create-class-computed-test.js +++ b/tests/unit/create-class-computed-test.js @@ -140,13 +140,13 @@ module('Unit | create class computed', function(hooks) { } }); - assert.equal(observerCallback.callCount, 2); + assert.equal(observerCallback.callCount, 3); assert.equal(callback.callCount, 2); subject.set('test5', 'test6'); - assert.equal(observerCallback.callCount, 3); + assert.equal(observerCallback.callCount, 4); subject.get('computed'); @@ -156,7 +156,7 @@ module('Unit | create class computed', function(hooks) { subject.get('computed'); - assert.equal(observerCallback.callCount, 3); + assert.equal(observerCallback.callCount, 4); assert.equal(callback.callCount, 4); });