HTML boolean attributes break dynamic expressions
thomasperi opened this issue · comments
Boolean attributes such as the checked
attribute on a checkbox seem unable to be set by dynamic expressions.
Example:
This renders and behaves as expected when the checked
attribute is static:
html`<input type="checkbox"
${data.foo ? 'checked' : ''}
@input="${e => data.foo = e.target.checked}"
/>`
However, if we make the checked
attribute dynamic, two things go wrong:
html`<input type="checkbox"
${() => data.foo ? 'checked' : ''}
@input="${e => data.foo = e.target.checked}"
/>`
(1) It renders like this in the browser, with an unchecked checkbox followed by some mangled code as plain text. (The name of the attribute, checked
, seems to replace the value of the next attribute, @input
.)
☐ @input="checked" />
(2) The @input
event doesn't fire when the checkbox is clicked.
Workaround:
Checkboxes can be made to work by making the checked
attribute static and then manipulating the checkbox DOM element directly when the value changes, with $on
.
Here's a generalized implementation of the workaround that I've only tested with checkboxes:
function booleanHack(data, prop, attr) {
let hackAttr = `boolean-hack="${prop}"`;
data.$on(prop, () => {
document.querySelectorAll(`[${hackAttr}]`).forEach(el => {
el[attr] = data[prop];
});
});
return hackAttr;
}
html`<input type="checkbox"
${booleanHack(data, 'foo', 'checked')}
${data.foo ? 'checked' : ''}
@input="${e => data.foo = e.target.checked}"
/>`
This is working as expected. In arrow (just like in React or Vue) you cannot use dynamic expressions to create new attributes, but you can effect whether a given attribute is rendered or not by assigning it to a falsey
value:
Thanks, but that way has a different problem: Once I interact with the checkbox, it breaks. I can turn the checkbox on and off with the button initially, but once I click the checkbox itself, the button can't change it anymore.
@thomasperi this should all be working now. Checkboxes now set the internal IDL attribute rather than the checked attribute: https://codepen.io/justin-schroeder/pen/JjBJXpW