From e2d170206f84740a05fb8f99e4a507122d7b87bb Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Tue, 18 Apr 2017 12:52:39 -0700 Subject: [PATCH] Process paths regardless of accessor, & loop on computeLinkedPaths. Fixes #4542 --- lib/mixins/property-effects.html | 60 +++++++++++++------------------- test/unit/path-effects.html | 8 +++-- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/lib/mixins/property-effects.html b/lib/mixins/property-effects.html index 7241725d1f..560d9cf312 100644 --- a/lib/mixins/property-effects.html +++ b/lib/mixins/property-effects.html @@ -371,12 +371,13 @@ */ function runComputedEffects(inst, changedProps, oldProps, hasPaths) { let computeEffects = inst.__computeEffects; - if (computeEffects) { - let inputProps = changedProps; - while (runEffects(inst, computeEffects, inputProps, oldProps, hasPaths)) { + let inputProps = changedProps; + while (inputProps) { + computeEffects && runEffects(inst, computeEffects, inputProps, oldProps, hasPaths); + computeLinkedPaths(inst, inputProps, hasPaths); + if ((inputProps = inst.__dataPending)) { Object.assign(oldProps, inst.__dataOld); Object.assign(changedProps, inst.__dataPending); - inputProps = inst.__dataPending; inst.__dataPending = null; } } @@ -416,21 +417,16 @@ function computeLinkedPaths(inst, changedProps, hasPaths) { let links; if (hasPaths && (links = inst.__dataLinkedPaths)) { - const cache = inst.__dataTemp; let link; for (let a in links) { let b = links[a]; for (let path in changedProps) { if (Polymer.Path.isDescendant(a, path)) { link = Polymer.Path.translate(a, b, path); - cache[link] = changedProps[link] = changedProps[path]; - let notifyProps = inst.__dataToNotify || (inst.__dataToNotify = {}); - notifyProps[link] = true; + inst._setPendingPropertyOrPath(link, changedProps[path], true, true); } else if (Polymer.Path.isDescendant(b, path)) { link = Polymer.Path.translate(b, a, path); - cache[link] = changedProps[link] = changedProps[path]; - let notifyProps = inst.__dataToNotify || (inst.__dataToNotify = {}); - notifyProps[link] = true; + inst._setPendingPropertyOrPath(link, changedProps[path], true, true); } } } @@ -1292,32 +1288,28 @@ */ _setPendingPropertyOrPath(path, value, shouldNotify, isPathNotification) { let rootProperty = Polymer.Path.root(Array.isArray(path) ? path[0] : path); - let hasAccessor = this.__dataHasAccessor && this.__dataHasAccessor[rootProperty]; - let isPath = (rootProperty !== path); - if (hasAccessor) { - if (isPath) { - if (!isPathNotification) { - // Dirty check changes being set to a path against the actual object, - // since this is the entry point for paths into the system; from here - // the only dirty checks are against the `__dataTemp` cache to prevent - // duplicate work in the same turn only. Note, if this was a notification - // of a change already set to a path (isPathNotification: true), - // we always let the change through and skip the `set` since it was - // already dirty checked at the point of entry and the underlying - // object has already been updated - let old = Polymer.Path.get(this, path); - path = /** @type {string} */ (Polymer.Path.set(this, path, value)); - // Use property-accessor's simpler dirty check - if (!path || !super._shouldPropertyChange(path, value, old)) { - return false; - } + if (rootProperty !== path) { + if (!isPathNotification) { + // Dirty check changes being set to a path against the actual object, + // since this is the entry point for paths into the system; from here + // the only dirty checks are against the `__dataTemp` cache to prevent + // duplicate work in the same turn only. Note, if this was a notification + // of a change already set to a path (isPathNotification: true), + // we always let the change through and skip the `set` since it was + // already dirty checked at the point of entry and the underlying + // object has already been updated + let old = Polymer.Path.get(this, path); + path = /** @type {string} */ (Polymer.Path.set(this, path, value)); + // Use property-accessor's simpler dirty check + if (!path || !super._shouldPropertyChange(path, value, old)) { + return false; } - this.__dataHasPaths = true; } + this.__dataHasPaths = true; return this._setPendingProperty(path, value, shouldNotify); } else { - if (isPath) { - Polymer.Path.set(this, path, value); + if (this.__dataHasAccessor && this.__dataHasAccessor[rootProperty]) { + return this._setPendingProperty(path, value, shouldNotify); } else { this[path] = value; } @@ -1548,8 +1540,6 @@ this.__dataHasPaths = false; // Compute properties runComputedEffects(this, changedProps, oldProps, hasPaths); - // Compute linked paths - computeLinkedPaths(this, changedProps, hasPaths); // Clear notify properties prior to possible reentry (propagate, observe), // but after computing effects have a chance to add to them let notifyProps = this.__dataToNotify; diff --git a/test/unit/path-effects.html b/test/unit/path-effects.html index b2db181140..c208b2d8b9 100644 --- a/test/unit/path-effects.html +++ b/test/unit/path-effects.html @@ -898,11 +898,15 @@ assert.equal(el.xChanged.callCount, 1); assert.equal(el.yChanged.callCount, 1); assert.equal(el.aChanged.callCount, 1); - el.unlinkPaths('y'); el.set('a.foo', 2); assert.equal(el.xChanged.callCount, 2); - assert.equal(el.yChanged.callCount, 1); + assert.equal(el.yChanged.callCount, 2); assert.equal(el.aChanged.callCount, 2); + el.unlinkPaths('y'); + el.set('a.foo', 3); + assert.equal(el.xChanged.callCount, 3); + assert.equal(el.yChanged.callCount, 2); + assert.equal(el.aChanged.callCount, 3); }); test('link two arrays', function() {