Search code examples
javascriptpolymerweb-componentlit-element

LitElement remove item from list


When the page first loads, the delete buttons generated by the code below work as expected. However, if you alter the text in one of the <textarea> elements, the delete button no longer works correctly. How can I fix this?

import { LitElement, html } from 'lit-element';

class MyElement extends LitElement {
  static get properties() {
    return {
      list: { type: Array },
    };
  }
  constructor() {
    super();
    this.list = [
      { id: "1", text: "hello" },
      { id: "2", text: "hi" },
      { id: "3", text: "cool" },
    ];
  }
  render() {
    return html`${this.list.map(item =>
        html`<textarea>${item.text}</textarea><button id="${item.id}" @click="${this.delete}">X</button>`
    )}`;
  }
  delete(event) {
    const id = event.target.id;
    this.list = this.list.filter(item => item.id !== id);
  }
}
customElements.define("my-element", MyElement);

Solution

  • I'm not sure of the exact cause, but I think it has to do with the way lit-html decides which DOM elements to remove when rendering a list with fewer items than the previous render. The solution is to use the repeat directive. It takes as its second argument a function that helps lit-html identify which DOM elements correspond to which items in the array:

    import { repeat } from 'lit-html/directives/repeat.js'
    
    // ...
    render(){
      return html`
        ${repeat(this.list, item => item.id,
          item => html`<textarea>${item.text}</textarea><button id="${item.id}" @click="${this.delete}">X</button><br>`
        )}
      `;
    }