diff --git a/lib/mixins/properties-changed.html b/lib/mixins/properties-changed.html index 4163e5cb51..d5e009fb1b 100644 --- a/lib/mixins/properties-changed.html +++ b/lib/mixins/properties-changed.html @@ -55,11 +55,11 @@ /** * Creates property accessors for the given property names. - * @param {Array} props Array of names of accessors. + * @param {object} props Object whose keys are names of accessors. */ static createProperties(props) { - for (let i = 0; i < props.length; i++) { - this.prototype._createPropertyAccessor(props[i]); + for (let prop in props) { + this.prototype._createPropertyAccessor(prop); } } @@ -136,6 +136,7 @@ */ ready() { this.__dataReady = true; + this._flushProperties(); } /** @@ -237,19 +238,12 @@ _invalidateProperties() { if (!this.__dataInvalid && this.__dataReady) { this.__dataInvalid = true; - microtask.run(() => this._validateProperties()); - } - } - - /** - * Changes are processed at microtask timing, but this method can be - * calleed to force any pending changes to be immediately processed. - * @protected - */ - _validateProperties() { - if (this.__dataInvalid) { - this.__dataInvalid = false; - this._flushProperties(); + microtask.run(() => { + if (this.__dataInvalid) { + this.__dataInvalid = false; + this._flushProperties(); + } + }); } } @@ -284,9 +278,11 @@ * @protected */ _flushProperties() { - let changedProps = this.__dataPending; - this.__dataPending = null; - this._propertiesChanged(this.__data, changedProps, this.__dataOld); + if (this.__dataPending && this.__dataOld) { + let changedProps = this.__dataPending; + this.__dataPending = null; + this._propertiesChanged(this.__data, changedProps, this.__dataOld); + } } /** @@ -384,17 +380,30 @@ /** * Sets a typed value to an HTML attribute on a node. * - * If the value is `undefined`, the attribute will be removed. + * This method calls the `_serializeValue` method to convert the typed + * value to a string. If the `_serializeValue` method returns `undefined`, + * the attribute will be removed (this is the default for boolean + * type `false`). * * @param {Element} node Element to set attribute to. * @param {*} value Value to serialize. * @param {string} attribute Attribute name to serialize to. */ _valueToNodeAttribute(node, value, attribute) { - if (!value && value !== '' && value !== 0) { + const str = this._serializeValue(value); + if (str === undefined) { node.removeAttribute(attribute); } else { - node.setAttribute(attribute, value === true ? '' : value); + node.setAttribute(attribute, str); + } + } + + _serializeValue(value) { + switch (typeof value) { + case 'boolean': + return value ? '' : undefined; + default: + return value != null ? value.toString() : undefined; } } @@ -434,7 +443,7 @@ * @protected */ _attributeForProperty(property) { - return property; + return property.toLowerCase(); } /**