Lit-html: Asynchronous method in a conditional attribute notation

Created on 6 Oct 2018  路  5Comments  路  Source: Polymer/lit-html

I am trying to use the conditional attribute notation with an async function, something like that :

<span ?special="${this.asyncMethodThatReturnsTrueOrFalse()}">...</span>

However It seems that lit-html will always evaluate this expression as true even if the method returns false (minimal example).

High Bug

Most helpful comment

It would most definitely be a nice feature to have! I'm just arguing that I'd modify the until directive to support attributes (and boolean attributes) so we can do

<button ?inactive=${until(this.isCardInactive(index), false)}>${cardId}</button>

All 5 comments

Thanks for the reproduction @vdegenne!

At the moment only NodeParts handle promises and other types, AttributePart, PropertyPart, EventPart and BooleanAttributePart take the value as-is without special handling for promises, iterables, nodes etc.

In my opinion that shouldn't change. For boolean attributes, changing the behaviour would give unexpected consequences when trying to set an attribute depending on whether a value is truthy or not. That'll work for any value, except for promises (or rather: any value with a then property) because for those we'll look at the truthiness of the value they eventually get fulfilled with.
It's of course true that one can always write

<span ?special=${this.somePromise != null}>

which will always work with or without the change. When I see a template with

<span ?special=${this.something}>

I interpret that as

if (this.something) {
  spanEl.setAttribute('special', '');
} else {
  spanEl.removeAttribute('special');
}

so in my mind the behaviour described in the OP is very much expected behaviour.


To support promises in the (boolean) attribute part we could easily update the until directive to support all part types and not just NodeParts. Right now this directive makes use of the fact that NodePart supports promises out of the box, but we could update until to subscribe to the promise itself.

This feels more correct to me for two reasons:

  1. I explicitly declare that I want to use the async value of the promise, not the fact that the promise is present
  2. This allows me to give a default value. If BooleanAttributePart automatically handles promises, I cannot declare whether I want the attribute to be present or not while the promise is unresolved.

@bgotink The reason why I used an asynchronous method here was because I needed the template to fully render. this.asyncMethodThatReturnsTrueOrFalse() is a method in a LitElement element. This method waits the dom to fully render and returns true or false based on an index :

{
  async isCardInactive(index) {
    await this.updateComplete;
    const card = this.shadowRoot.querySelectorAll('x-card')[index];
    await card.updateComplete;
    return !card._active;
  }

  render() {
    return html`
      <style>button[inactive] { opacity: .4 }</style>
      ${repeat(this.cardsIds, (cardId, index) => html`
        <button ?inactive=${isCardInactive(index)}>${cardId}</button>
      `}
      ${repeat(this.cardsIds, cardId => html`<x-card .cardId=${cardId}></x-card>`)}
    `;
  }
}

It's my bad that I didn't specify the context. But I agree this behavior was very much expected. This issue was more like a feature request as it would save the writing of an extra method that requires dom manipulation.

It would most definitely be a nice feature to have! I'm just arguing that I'd modify the until directive to support attributes (and boolean attributes) so we can do

<button ?inactive=${until(this.isCardInactive(index), false)}>${cardId}</button>

Closed by #555

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pjtatlow picture pjtatlow  路  3Comments

pietmichal picture pietmichal  路  4Comments

Christian24 picture Christian24  路  4Comments

fopsdev picture fopsdev  路  5Comments

MVSICA-FICTA picture MVSICA-FICTA  路  5Comments