New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes property options to support converter
#369
Conversation
Fixes #264 Changes `type` to be only a hint to the `converter` option which has the previous `type` functionality, an object with `toAttribute` and `fromAttribute` or just a function which is `fromAttribute`. In addition to the `value` these functions now also get the property's `type`. Also provides a default converter that supports `Boolean`, `String`, `Number`, `Object`, and `Array` out of the box. In addition, numbers and strings now become `null` if their reflected attribute is removed.
README.md
Outdated
| keys. | ||
| * `type`: Indicates the type of the property. This is used only as a hint for the | ||
| `converter` to determine how to serialize and deserialize the attribute | ||
| to/from a property. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add:
Default converters are provided for
String,Number, ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added to converter section.
src/lib/updating-element.ts
Outdated
| return value ? '' : null; | ||
| case Object: | ||
| case Array: | ||
| return JSON.stringify(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on experience with this being a footgun for users, consider anything better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this #375 to ensure this is well documented.
src/lib/updating-element.ts
Outdated
| return value; | ||
| } | ||
| // Note: special case `Boolean` so users can use it as a `type`. | ||
| const converter = options && options.converter || defaultConverter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't need a null check since there's a defaultPropertyDeclaration?
Remove superfluous null checks
Previously, when an attribute changed as a result of a reflecting property changing, the property was prevented from mutating again as can happen when a custom `converter` is used. Now, the oppose is also true. When a property changes as a result of an attribute changing, the attribute is prevented from mutating again This change helps ensure that when a user calls `setAttribute`, a `converter.toAttribute` does not cause the attribute to immediately mutate. This is unexpected behavior and this change discourages it.
README.md
Outdated
| `converter` to determine how to serialize and deserialize the attribute | ||
| to/from a property. Note, when a property changes and the converter is used | ||
| to update the attribute, the property is never updated again as a result of | ||
| the attribute changing, and visa versa. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| the attribute changing, and visa versa. | |
| the attribute changing, and vice versa. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
src/lib/updating-element.ts
Outdated
| @@ -15,27 +15,28 @@ | |||
| /** | |||
| * Converts property values to and from attribute values. | |||
| */ | |||
| export interface AttributeSerializer<T = any> { | |||
| export interface ComplexAttributeConverter<Type = any, TypeHint = any> { | |||
|
|
|||
| /** | |||
| * Deserializing function called to convert an attribute value to a property | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO Deserializing and Deserializing is a confusing terminology.
Is it still needed after this change ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
README.md
Outdated
| `converter` to determine how to serialize and deserialize the attribute | ||
| to/from a property. Note, when a property changes and the converter is used | ||
| to update the attribute, the property is never updated again as a result of | ||
| the attribute changing, and visa versa. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docs/_guide/properties.md should also be updated, see #370
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this #375 to ensure this is well documented.
| @@ -416,41 +446,44 @@ export abstract class UpdatingElement extends HTMLElement { | |||
| name: PropertyKey, value: unknown, | |||
| options: PropertyDeclaration = defaultPropertyDeclaration) { | |||
| const ctor = (this.constructor as typeof UpdatingElement); | |||
| const attrValue = ctor._propertyValueToAttribute(value, options); | |||
| if (attrValue !== undefined) { | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this removed for a reason? Apparently undefined was being used as a sentinel return value from toAttribute meaning "no change". Should we keep this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done and added test.
src/lib/updating-element.ts
Outdated
| if (options.reflect === true) { | ||
| // Add to reflecting properties set if `reflect` is true and the property | ||
| // is not reflecting from the attribute | ||
| if (options.reflect === true && !(this._updateState & STATE_IS_REFLECTING)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be nice to separate STATE_IS_REFLECTING_TO_ATTRIBUTE and STATE_IS_REFLECTING_TO_PROPERTY; I think they should be mutually exclusive timing-wise, but the setting/reading the flags are paired to two different use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Ensure Object/Array properties respect `undefined` (no change to attribute) and `null` (remove attribute) values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Won't merge until Sauce service incident is resolved and tests pass.
Shouldn't numbers and strings become |
Fixes #264
Changes
typeto be only a hint to theconverteroption which has the previoustypefunctionality, an object withtoAttributeandfromAttributeor just a function which isfromAttribute. In addition to thevaluethese functions now also get the property'stype.Also provides a default converter that supports
Boolean,String,Number,Object, andArrayout of the box.In addition, numbers and strings now become
nullif their reflected attribute is removed.