Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to observe property changes with LitElement

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")
  }
like image 251
grohjy Avatar asked May 18 '18 09:05

grohjy


2 Answers

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);
like image 111
Michał Pietraszko Avatar answered Sep 25 '22 15:09

Michał Pietraszko


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.

like image 44
6pi Avatar answered Sep 22 '22 15:09

6pi