justin-schroeder / arrow-js

Reactivity without the framework

Home Page:https://arrow-js.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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:

https://codepen.io/justin-schroeder/pen/JjBJXpW

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