WebUI: Add a documentation on -changed event handlers in Lit
The documentation already covered how 2 way bindings can be converted from Polymer, but without the Polymer context it is not obvious to CL authors that -changed events differ from events like click, keydown etc in that they should not perform updates to the DOM, since the element may not be done updating yet. Document that such handlers may update properties on the parent but generally should not update the DOM directly, instead deferring such updates to the updated() lifecycle callback. Bug: 40943652 Change-Id: I1b061dc5ac80bfea7d9d22b5c8506195c60bdaf9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5725763 Commit-Queue: Rebekah Potter <rbpotter@chromium.org> Reviewed-by: Demetrios Papadopoulos <dpapad@chromium.org> Cr-Commit-Position: refs/heads/main@{#1330579}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
93fa4397a5
commit
1524baaf37
@ -63,6 +63,79 @@ Specific features of `CrLitElement` include:
|
||||
in Polymer - i.e. property `fooBar` will be mapped to attribute `foo-bar`,
|
||||
not the Lit default of `foobar`
|
||||
|
||||
## Lit Data Bindings and handling `-changed` events
|
||||
As noted above, `CrLitElement` forces an initial synchronous render in
|
||||
`connectedCallback()`. This means child elements may initialize properties
|
||||
with `notify: true` and then fire `-changed` events for these properties in
|
||||
`updated()` as soon as they are connected, which may occur before the parent
|
||||
element has finished its first update.
|
||||
|
||||
One consequence of this is that `-changed` event handlers cannot assume that
|
||||
the element has completed its first update when the `-changed` event is
|
||||
received, and should not make any changes to the element's DOM until after
|
||||
waiting for the element's `updateComplete` promise. This means such handlers
|
||||
must either (1) be async and `await this.updateComplete;` before running any
|
||||
code that updates the element's DOM, or (2) only update properties on the
|
||||
parent in response to the child's property change, and perform resulting UI
|
||||
updates in the `updated()` lifecycle method instead.
|
||||
|
||||
Note that if the parent property being updated is protected or private, a cast
|
||||
will be necessary to check for changes to the property in `changedProperties`.
|
||||
This is also demonstrated in the example below.
|
||||
|
||||
Suppose the Lit child has a property with `notify: true` as follows:
|
||||
```
|
||||
static override get properties() {
|
||||
return {
|
||||
foo: {
|
||||
type: Boolean,
|
||||
notify: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
This property is also bound to a parent element that listens for the
|
||||
`-changed` event as follows:
|
||||
```
|
||||
<foo-child ?foo="${this.foo_}" on-foo-changed="${this.onFooChanged_}">
|
||||
</foo-child>
|
||||
<demo-child id="demo"></demo-child>
|
||||
```
|
||||
|
||||
The parent TypeScript code could look like this:
|
||||
```
|
||||
static override get properties() {
|
||||
return {
|
||||
foo_: {type: Boolean},
|
||||
};
|
||||
}
|
||||
|
||||
protected foo_: boolean = true;
|
||||
|
||||
onFooChanged_(e: CustomEvent<{value: boolean}>) {
|
||||
// Updates the parent's property that is bound to the child.
|
||||
this.foo_ = e.detail.value;
|
||||
}
|
||||
|
||||
override updated(changedProperties: PropertyValues<this>) {
|
||||
super.updated(changedProperties);
|
||||
|
||||
// Cast necessary to check for changes to protected/private properties.
|
||||
const changedPrivateProperties =
|
||||
changedProperties as Map<PropertyKey, unknown>;
|
||||
|
||||
// Updates the DOM when |foo_| changes.
|
||||
if (changedPrivateProperties.has('foo_')) {
|
||||
if (this.foo_) {
|
||||
this.$.demo.show();
|
||||
} else {
|
||||
this.$.demo.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Lit and Polymer Data Bindings Compatibility
|
||||
Two-way bindings are not natively supported in Lit. As mentioned above,
|
||||
basic compatibility is provided by the `CrLitElement` base class’s
|
||||
|
Reference in New Issue
Block a user