Back to Lit

10

packages/lit-dev-content/site/tutorials/content/wc-to-lit/10.md

latest3.5 KB
Original Source

Event Listeners

Now that you have gotten rid of the <template> element in index.html, refactor the code to take advantage of Lit template features in the newly-defined render() method. You can start by leveraging Lit's event listener binding syntax:

rating-element.<ts-js></ts-js>

html
<button
    class="thumb_down"
    @click=${() => {this.vote = 'down'}}>
...
<button
    class="thumb_up"
    @click=${() => {this.vote = 'up'}}>

Lit templates can add an event listener to a node with the @EVENT_NAME binding syntax where, in this case, you update the vote property every time these buttons are clicked.

{% aside "info" %}

You can learn more about the Lit binding syntax in the Lit Expressions documentation.

{% endaside %}

Next:

  • Clean up the _boundOn[Up|Down]Click class members.
  • Clean up the event logic in connectedCallback.
  • Remove disconnectedCallback.
  • Remove the _on[Up|Down]Click methods.

rating-element.<ts-js></ts-js>

{% switchable-sample %}

ts
export class RatingElement extends HTMLElement {
  private _rating = 0;
  private _vote: 'up'|'down'|null = null;

  connectedCallback() {
    this.attachShadow({mode: 'open'});
    this.render();
  }

  // remove disonnectedCallback and _onUpClick and _onDownClick
  ...
}
js
export class RatingElement extends HTMLElement {
  _rating = 0;
  _vote = null;

  connectedCallback() {
    this.attachShadow({mode: 'open'});
    this.render();
  }

  // remove disonnectedCallback and _onUpClick and _onDownClick
  ...
}

{% endswitchable-sample %}

You were able to remove:

  • The click listener logic from all three callbacks.
  • The disconnectedCallback entirely.
  • All of the DOM initialization code from the connectedCallback making it look much more elegant.
  • _onUpClick and _onDownClick listener methods.

Rendering Property Updates

Finally, update the property setters to utilize the render method so that the DOM can update when either the properties or attributes change:

rating-element.<ts-js></ts-js>

{% switchable-sample %}

ts
set rating(value) {
  this._rating = value;
  // remove the logic for imperatively setting the innerText
  // since it's handled in render()
  this.render();
}

...

set vote(newValue) {
  ...

  this._vote = newValue;
  this.setAttribute('vote', newValue!);
  // call this.render() at the end of the setter
  this.render();
}
js
set rating(value) {
  this._rating = value;
  // remove the logic for imperatively setting the innerText
  // since it's handled in render()
  this.render();
}

...

set vote(newValue) {
  ...

  this._vote = newValue;
  this.setAttribute('vote', newValue);
  // call this.render() at the end of the setter
  this.render();
}

{% endswitchable-sample %}

{% aside "warn" %}

This is not the most efficient way to update the DOM.

Synchronously calling render() in the setters of rating and vote is not the most efficient way to update the DOM, but it is a good way to illustrate where LitElement calls render() (next step).

{% endaside %}

Here, you:

  • Removed the DOM update logic from the rating setter.
  • Added a call to render from the vote setter.

Now the template is much more readable as you now can see where the bindings and event listeners are applied.

You should have a functioning <rating-button> that should look like this when the upvote is pressed!