diff --git a/lib/mixins/property-effects.js b/lib/mixins/property-effects.js index c7e68cff47..857e786fb9 100644 --- a/lib/mixins/property-effects.js +++ b/lib/mixins/property-effects.js @@ -622,7 +622,9 @@ function applyBindingValue(inst, node, binding, part, value) { inst._enqueueClient(node); } } - } else { + } else if (!legacyNoBatch || inst.__dataReady) { + // In legacy no-batching mode, bindings applied before dataReady are + // equivalent to the "apply config" phase, which only set managed props inst._setUnmanagedPropertyToNode(node, prop, value); } } @@ -1555,7 +1557,30 @@ export const PropertyEffects = dedupingMixin(superClass => { */ _flushProperties() { this.__dataCounter++; - super._flushProperties(); + if (legacyNoBatch && !this.__dataReady) { + // The first time this element is being flushed, propagate pending + // data down the tree first; this approximates 1.x's distributeConfig + this._propagatePropertyChanges(this.__dataPending, {}, false); + // Flushing clients causes this element to become __dataReady + this._flushClients(); + // Capture element data and flush properties one-by one to defeat + // Polymer 2.x's batched _propertiesChanged scheme; this approximates + // 1.x's applyConfig + const changedProps = this.__data; + const notify = this.__dataToNotify; + this.__data = {}; + this.__dataPending = this.__dataToNotify = null; + for (let prop in changedProps) { + const value = changedProps[prop]; + this.__data[prop] = value; + this.__dataPending = {[prop]: value}; + this.__dataOld = {}; + this.__dataToNotify = {[prop]: notify && notify[prop]}; + super._flushProperties(); + } + } else { + super._flushProperties(); + } this.__dataCounter--; } @@ -1698,12 +1723,21 @@ export const PropertyEffects = dedupingMixin(superClass => { // ---------------------------- let hasPaths = this.__dataHasPaths; this.__dataHasPaths = false; + let notifyProps; // Compute properties - runComputedEffects(this, changedProps, oldProps, 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; - this.__dataToNotify = null; + if (legacyNoBatch) { + // When not batching, computed effects may re-enter, so capture + // notifying properties early + notifyProps = this.__dataToNotify; + this.__dataToNotify = null; + runEffects(this, this[TYPES.COMPUTE], changedProps, oldProps, hasPaths); + } else { + runComputedEffects(this, changedProps, oldProps, hasPaths); + // Clear notify properties prior to possible reentry (propagate, observe), + // but after computing effects have a chance to add to them + notifyProps = this.__dataToNotify; + this.__dataToNotify = null; + } // Propagate properties to clients this._propagatePropertyChanges(changedProps, oldProps, hasPaths); // Flush clients diff --git a/test/runner.html b/test/runner.html index 8f67390d67..341b02899d 100644 --- a/test/runner.html +++ b/test/runner.html @@ -31,6 +31,8 @@ 'unit/template-stamp.html', 'unit/strict-template-policy.html', 'unit/property-effects.html', + 'unit/property-effects.html?legacyUndefined=true', + 'unit/property-effects.html?legacyUndefined=true&legacyNoBatch=true', 'unit/property-effects-template.html', 'unit/path-effects.html', 'unit/shady.html', diff --git a/test/unit/property-effects-elements.js b/test/unit/property-effects-elements.js index 7986f2a6f7..0e0f6094d6 100644 --- a/test/unit/property-effects-elements.js +++ b/test/unit/property-effects-elements.js @@ -298,7 +298,9 @@ Polymer({ }, $computeTrickyFunctionFromLiterals: function(num, str) { - return this.computeFromLiterals(num, str); + assert.equal(num, 3); + assert.equal(str, 'foo'); + return num + str; }, computeFromTrickyLiterals: function(a, b) { diff --git a/test/unit/property-effects.html b/test/unit/property-effects.html index 087023914f..37b211b85a 100644 --- a/test/unit/property-effects.html +++ b/test/unit/property-effects.html @@ -26,9 +26,13 @@