lit

Keyed directive does not respond to attribute change


I am trying to use the keyed directive in lit element. I don't want to do the ?action=${action} because just adding the action attribute or removing the action attribute is cleaner for true or false. However, the keyed directive does seem to reset the element when I add or remove the action attribute. Any ideas, please, on how to make this work without the hacky ?action=${action}?


      ${keyed(this.active, html`                                                                                          
        <add-transaction                                                                                                    
          @add-catergory=${() => this.openAddCatergory()}                                                                   
          @save-trans=${this.#saveTrans}                                                                                    
          .label=${this.label}                                                                                              
          id="add-transaction"></add-transaction>`)} 
  _loadNewTransactionPage() {
    const el = this.renderRoot.querySelector('#add-transaction');
    el.setAttribute('active', '');
  }

Solution

  • keyed() has nothing to do with, and knows nothing about, attributes. The key is any JS value (not necessarily even a property of an element) and if it changes the template instance is cleared and re-rendered.

    If you do want to key off an attribute, you need to pass an attribute value to keyed() and you need to re-render when that attribute changes. Lit's reactive properties will do just that. So make a reactive property out of action (presumably it's "action", but you also use "active" in your code).

    class MyElement extends LitElement {
      @property() action;
    
      render() {
        return html`
          ${keyed(this.action, html`                                                                                          
            <add-transaction                                                                                                    
              @add-catergory=${() => this.openAddCatergory()}                                                                   
              @save-trans=${this.#saveTrans}                                                                                    
              .label=${this.label}                                                                                              
              id="add-transaction"></add-transaction>`)} 
        `;
      }
    }
    

    Now when action changes on a MyElement, the template will re-render and the new value of this.action will be used as the key.

    This in only combining reactive properties with keyed(). Again, keyed() can be used with any value from anywhere.