Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lit-Element: which event to use for DOM updates?

The documentation over at github.com/Polymer/lit-element describes the lifecycl, if a property of some lit-element is changed. However, I can not seem to find any documentation about a lifecycle if the DOM content of the element is changed.

So assume I have some nested DOM structure and my outermost element should display something based on the DOM content. For sake of simplicity the example below will just display the number of child-elements of the given type.

Now at some point my application inserts a new nested element (click the test button below). At this point I would like to update the shown count.

From my tests it seems that render() is not called again in that case, neither is updated().

Which event do I need to listen or which function do I need to implement for to recognize such a change?

My only current workaround is to use requestUpdate() manually after the DOM update, but I think such changes should be handled by lit-element itself.

  document.querySelector( 'button' )
          .addEventListener( 'click', () => {
            const el = document.querySelector( 'my-element' );
            el.insertAdjacentHTML( 'beforeend', '<my-nested-element>new addition</my-nested-element>' );
          })
my-element, my-nested-element {
  display: block;
}
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@latest/webcomponents-loader.js"></script>

<!-- Works only on browsers that support Javascript modules like Chrome, Safari, Firefox 60, Edge 17 -->
<script type="module">
  import {LitElement, html} from 'https://unpkg.com/@polymer/lit-element/lit-element.js?module';

  class MyElement extends LitElement {
    constructor(){
      super();
      this.number = this.querySelectorAll( 'my-nested-element' ).length;
    }
  
    render() {
      return html`<p>number of my-nested-element: ${this.number}</p> 
                  <slot></slot>`;
    }  
  }
  customElements.define('my-element', MyElement);
  
	class MyNestedElement extends LitElement {
    render() {
      return html`<slot></slot>`;
    }  
  }
  customElements.define('my-nested-element', MyNestedElement);
</script>

<my-element>
  <my-nested-element>first</my-nested-element>
  <my-nested-element>second</my-nested-element>
</my-element>

<button>test</button>
like image 258
Sirko Avatar asked Nov 21 '18 10:11

Sirko


People also ask

How do you update lit element?

If hasChanged returned true , requestUpdate fires, and the update proceeds. To manually start an element update, call requestUpdate with no parameters. To implement a custom property setter that supports property options, pass the property name and its previous value as parameters.

How do you observe property changes with LitElement?

You can use the changedProperties.has("<propName>") to find out if your property has been changed or not. If your property has been changed, then use changedProperties. get("<propName>") to get access to the old value. A type assertion is needed here to match the static type defined by the declared property.

What is the life cycle of lit elements?

LitElement performs rendering during an update. updated() and firstUpdated() are lifecycle callbacks that are called after updates. firstUpdated() is only called once, and it's intended to be used to do one time setup that depends on an update/render - like querying the shadow root for important elements.

What is lit in JavaScript?

Lit is a fast, lightweight, reactive framework for building web components that work just about anywhere. Let's get started with Lit. Lit is one of the more interesting front-end JavaScript frameworks for reactive programming.


1 Answers

In order to detect a new element inserted from the Light DOM through a <slot> element, you can listen to slotchange events on the <slot> element, or on the Shadow DOM root itself.

See the running example below:

document.querySelector('button').onclick = () => 
  document.querySelector('my-element').insertAdjacentHTML('beforeend', '<my-nested-element>new addition</my-nested-element>');
  
my-element,
my-nested-element {
  display: block;
}
<script type="module">
  import {LitElement, html} from 'https://unpkg.com/@polymer/lit-element/lit-element.js?module';

  class MyElement extends LitElement {
    firstUpdated() {
      var shadow = this.shadowRoot
      var nb = shadow.querySelector( 'span#nb' )
      shadow.addEventListener( 'slotchange', () => 
        nb.textContent = this.querySelectorAll( 'my-nested-element').length 
      )    
    }
    render() {
      return html`<p>number of my-nested-element: <span id="nb"></span></p> 
                  <slot></slot>`;
    }  
  }
  customElements.define('my-element', MyElement);
</script>

<my-element>
  <my-nested-element>first</my-nested-element>
  <my-nested-element>second</my-nested-element>
</my-element>

<button>test</button>
like image 56
Supersharp Avatar answered Oct 17 '22 15:10

Supersharp