LitElement not updating checkbox in list
Asked Answered
B

1

7

I have a simple check list with a delete button for each item. When I check the first item and then delete it, the list updates, deleting the item, but the check box of the next item is checked. The properties of the next item are correct.

Here's my code:

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

class CheckList extends LitElement {
  static get properties() {
    return {
      items: { type: Array },
    };
  }

  constructor() {
    super();
    this.items = [
      {
        id: 1,
        text: 'Item 1',
        isDone: false,
      },
      {
        id: 2,
        text: 'Item 2',
        isDone: false,
      },
    ];

    this.toggleCheck = this.toggleCheck.bind(this);
    this.deleteItem = this.deleteItem.bind(this);
  }

  render() {
    return html`
      <ul>
        ${this.items.map(item => html`
          <li>
            <input
              type="checkbox"
              value=${item.id}
              ?checked=${item.isDone}
              @click=${this.toggleCheck}
            >
            ${item.text}
            <button @click=${this.deleteItem}>X</button>
          </li>
        `)}
      </ul>
    `;
  }

  toggleCheck(e) {
    const id = Number(e.target.value);

    this.items = this.items.map(item => {
      if (item.id === id) {
        item.isDone = !item.isDone;
      }

      return item;
    });
  }

  deleteItem(e) {
    const id = Number(e.target.parentNode.querySelector('input').value);

    this.items = this.items.filter(item => item.id !== id);
  }
}

customElements.define('check-list', CheckList);

https://stackblitz.com/edit/typescript-fylwxb

Believe answered 3/5, 2019 at 1:36 Comment(0)
I
16

This is because of the behavior of the checked attribute. According to MDN docs:

A Boolean attribute indicating whether or not this checkbox is checked by default (when the page loads). It does not indicate whether this checkbox is currently checked: if the checkbox’s state is changed, this content attribute does not reflect the change. (Only the HTMLInputElement’s checked IDL attribute is updated.)

In fact, in your example, the checked state of the input is not being toggled by this line:

?checked=${item.isDone}

but by the native behavior of the checkbox, which also sets the checked property to true. To prove this you can try to programmatically uncheck it after clicking on it:

// This won't have any effect if yourInputElement.checked is true
yourInputElement.removeAttribute('checked');

lit-html is probably reusing the input DOM node from the deleted line to render the subsequent line without creating a new one, thus keeping the checked property true.

The boolean attribute binding (?) only sets or removes the attribute. You should instead use the property binding (.) to correctly update HTMLInputElement’s checked property.

<input type="checkbox"
       value=${item.id}
       .checked=${item.isDone}
       @click=${this.toggleCheck}>
Istanbul answered 5/5, 2019 at 17:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.