Reputation: 2149
I don't know how to observe property changes in LitElement.
I've been trying these methods, but I couldn't get these to work:
static get properties() {
return {
temp1:String,
temp2: {
type:String,
observer: '_temp2Changed'
}
};
temp1Changed(newValue, oldValue){
console.log("temp1 changed")
}
_temp2Changed(newValue, oldValue){
console.log("temp2 changed")
}
Upvotes: 10
Views: 22662
Reputation: 121
Implement the shouldUpdate() method. Source here.
Controls whether an update should proceed. Implement
shouldUpdate
to specify which property changes should cause updates. By default, this method always returns true.
function shouldUpdate(changedProperties: Map<any, any>) {
changedProperties.forEach((oldValue, propName) => {
const newValue = JSON.stringify(this[propName]);
console.log(`${propName} changed. oldValue: ${oldValue} newValue: ${newValue}`);
});
return true;
}
Upvotes: 0
Reputation: 51
Properties 'hasChanged' option:
You can define this 'hasChanged' option in a property declaration within the static properties getter. Just like you do with 'type' option.
hasChanged should return true to update the element.
myProp: { hasChanged(newVal, oldVal) {
// compare newVal and oldVal
// return `true` if an update should proceed
}}
Chek it out here
Lifecycle method: updated
There is a lifecycle method named 'updated' that gets triggered every time any property changes.
This method receives as params the 'changedProperties' with their previous values so you can compare them to current values, then decide whatever you want to do with that.
Check out 'updated' documentation here.
Upvotes: 4
Reputation: 47
LitElement automatically re-renders every time the property changes, so long as the property is defined in your '_render' method.
This is noted in the LitElement readme:
React to changes: LitElement reacts to changes in properties and attributes by asynchronously rendering, ensuring changes are batched. This reduces overhead and maintains consistent state.
For example:
_render({firstName, lastName}) {
return html`
<div> Hello ${firstName} ${lastName} </div>
`
};
Will re-render every time your firstName and lastName properties change. I hope this provides a little bit of clarity.
Upvotes: 1
Reputation: 417
I personally override the "requestUpdate" method to be aware of a change before rendering.
My use-case is to intercept a change of a "label" attribute to trigger asynchronous data request.
Snippet below (in TypeScript):
@customElement('my-element')
export default class MyElement extends LitElement {
@property({type: String})
label: string | null = null;
@property({attribute: false})
private isLoading: boolean = false;
@property({attribute: false, noAccessor: true})
private data: MyData | null = null;
protected render() {/*some code*/}
requestUpdate(name?: PropertyKey, oldValue?: unknown) {
if(name && name == "label" && this.label !== oldValue) {
this.isLoading = true;
requestData(this.label, this._callbackData);
}
return super.requestUpdate(name, oldValue);
}
private _callbackData(data: MyData}) {
this.data = data;
this.isLoading = false;
}
}
In this way, my element is rendered only twice: one with the new label and loading as true then one other when data are available.
Upvotes: 4
Reputation: 6199
Version 0.6.0+
First, you have to specify element properties. You can do it by creating a static getter which returns an object including their names as keys and their attribute related configuration.
The updated
lifecycle method will be called when changed properties had caused a re-render. The first argument will return values before an update.
class MyComponent extends LitElement {
static get properties() {
return {
foo: {}
};
}
constructor() {
super();
this.foo = 0;
setInterval(() => this.foo++, 1000);
}
updated(changedProperties) {
console.log(changedProperties); // logs previous values
console.log(this.foo); // logs current value
}
render() {
return html`${this.foo}`;
}
}
customElements.define("my-component", MyComponent);
Upvotes: 12
Reputation: 2149
I found a solution from Polymer's PWA Starter kits.
Add following to your element definition:
_propertiesChanged(props, changed, oldProps) {
console.log("_propertiesChanged(props, changed, oldProps):");
console.log(props);
console.log(changed);
console.log(oldProps);
if (changed && 'temp1' in changed) {
console.log("if temp1:"+changed.temp1);
}
super._propertiesChanged(props, changed, oldProps); //This is needed here
}
console output:
_propertiesChanged(props, changed, oldProps):
{temp1: "newVal1", temp2: "val2"}
{temp1: "newVal1"}
{temp1: "val1"}
if temp1:newVal1
Upvotes: 0