Skip to content

Commit

Permalink
Adds legacyUndefined setting
Browse files Browse the repository at this point in the history
If `legacyUndefined` is set, multi-property observers, computed properties, and bindings will not be executed unless none of their dependencies is `undefined`. This matches Polymer 1 behavior.
  • Loading branch information
Steven Orvell committed Feb 7, 2019
1 parent 7823d8a commit 987ae2c
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
20 changes: 17 additions & 3 deletions lib/mixins/property-effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import { camelToDashCase, dashToCamelCase } from '../utils/case-map.js';
import { PropertyAccessors } from './property-accessors.js';
/* for annotated effects */
import { TemplateStamp } from './template-stamp.js';
import { sanitizeDOMValue } from '../utils/settings.js';
import { sanitizeDOMValue, legacyUndefined } from '../utils/settings.js';

// Monotonically increasing unique ID used for de-duping effects triggered
// from multiple properties in the same turn
let dedupeId = 0;

const NOOP = {};

/**
* Property effect types; effects are stored on the prototype using these keys
* @enum {string}
Expand Down Expand Up @@ -432,6 +434,10 @@ function runComputedEffects(inst, changedProps, oldProps, hasPaths) {
*/
function runComputedEffect(inst, property, props, oldProps, info) {
let result = runMethodEffect(inst, property, props, oldProps, info);
// Abort if method returns a no-op result
if (result === NOOP) {
return;
}
let computedProp = info.methodInfo;
if (inst.__dataHasAccessor && inst.__dataHasAccessor[computedProp]) {
inst._setPendingProperty(computedProp, result, true);
Expand Down Expand Up @@ -579,7 +585,10 @@ function runBindingEffect(inst, path, props, oldProps, info, hasPaths, nodeList)
} else {
let value = info.evaluator._evaluateBinding(inst, part, path, props, oldProps, hasPaths);
// Propagate value to child
applyBindingValue(inst, node, binding, part, value);
// Abort if value is a no-op result
if (value !== NOOP) {
applyBindingValue(inst, node, binding, part, value);
}
}
}

Expand Down Expand Up @@ -816,7 +825,7 @@ function runMethodEffect(inst, property, props, oldProps, info) {
let fn = context[info.methodName];
if (fn) {
let args = inst._marshalArgs(info.args, property, props);
return fn.apply(context, args);
return args === NOOP ? NOOP : fn.apply(context, args);
} else if (!info.dynamicFn) {
console.warn('method `' + info.methodName + '` not defined');
}
Expand Down Expand Up @@ -2215,6 +2224,11 @@ export const PropertyEffects = dedupingMixin(superClass => {
value = structured ? getArgValue(data, props, name) : data[name];
}
}
// When the `legacyUndefined` flag is enabled, pass a no-op value
// so that the observer, computed property, or compound binding is aborted.
if (legacyUndefined && value === undefined) {
return NOOP;
}
values[i] = value;
}
return values;
Expand Down
19 changes: 19 additions & 0 deletions lib/utils/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,22 @@ export let syncInitialRender = false;
export const setSyncInitialRender = function(useSyncInitialRender) {
syncInitialRender = useSyncInitialRender;
};

/**
* Setting to retain the legacy Polymer 1 behavior for multi-property
* observers around undefined values. Observers and computed property methods
* are not called until no argument is undefined.
*/
export let legacyUndefined = false;

/**
* Sets `legacyUndefined` globally for all elements to enable legacy
* multi-property behavior for undefined values.
*
* @param {boolean} useLegacyUndefined enable or disable legacy
* multi-property behavior for undefined.
* @return {void}
*/
export const setLegacyUndefined = function(useLegacyUndefined) {
legacyUndefined = useLegacyUndefined;
};

0 comments on commit 987ae2c

Please sign in to comment.