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);
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./edit/typescript-fylwxb
Share Improve this question edited May 3, 2019 at 1:55 dork asked May 3, 2019 at 1:36 dorkdork 4,5783 gold badges33 silver badges59 bronze badges1 Answer
Reset to default 17This 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
’schecked
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}>