loading...

re: Let's Build Web Components! Part 5: LitElement VIEW POST

FULL DISCUSSION
 

I am still confused on why I will want to convert properties to attributes and vice versa. Can you give me one use case?

 

Hey, sure

So, properties exist on the DOM, which is the browser's JavaScript object representation of the Document, but they don't exist at all in the document's HTML markup.

One big difference between the two is that (for the most part), CSS can't see the DOM, it can only see the markup.

@customElement('x-l')
class XElement extends LitElement {
  @property({ type: Boolean, reflect: true })
  schwifty = false;

  render() {
    return html`
      <button @click="${this.onClick}">
        Get ${this.schwifty ? 'un' : ''}schwifty
      </button>
    `;
  }

  onClick() {
    this.schwifty = !this.schwifty;
  }
}

Here, we use reflect: true in the property descriptor for XElement#schwifty to indicate that setting the property should reflect to the attribute.

That could be useful for a document author, for example with this css:

x-l[schwifty] {
  background: url('https://media.giphy.com/media/eNpXWzGIMRjIo4lXT8/giphy.gif');
}

Another use case along these lines could be setting a disabled attribute, or setting ARIA attributes based on an element's DOM state. I set the error attribute based on a caught error's message property in <stripe-elements>, as a convenience while debugging.

You can similarly think of cases where a component author would specifically not want to leak internal state outwards to the document, like when some intermediate value is observed so that it causes re-render, while remaining a private 'implementation detail' of the element:

const handleAsText = res => res.text();

@customElement("tpl-include")
export class TplInclude extends LitElement {
  @property({ attribute: false }) content;

  _template;

  @property({ type: String })
  get template() { return this._template; }
  set template(template) {
    let currentValue = this.template;
    this._template = template;
    this.fetchContent();
    this.requestUpdate('template', currentValue);
  }

  async fetchContent() {
    this.content =
      await fetch(this.template)
        .then(handleAsText);
  }

  render() {
    return (
        !this.content ? html`<span>Loading...</span>`
      :  html`${unsafeHTML(this.content)}`
    );
  }
}
 

Small edit to the second example: set content descriptor with attribute: false, It can only be set with a property now

Code of Conduct Report abuse