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











up vote
2
down vote

favorite












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>












share|improve this question
























  • you could listen to the slotchange event
    – Supersharp
    Nov 22 at 0:04










  • @Supersharp Thanks! After some fiddling with the details (seems I need to attach the event to the shadowRoot and not the element itself), this worked. If you put that into an answer, I'll gladly accept it.
    – Sirko
    Nov 22 at 8:09















up vote
2
down vote

favorite












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>












share|improve this question
























  • you could listen to the slotchange event
    – Supersharp
    Nov 22 at 0:04










  • @Supersharp Thanks! After some fiddling with the details (seems I need to attach the event to the shadowRoot and not the element itself), this worked. If you put that into an answer, I'll gladly accept it.
    – Sirko
    Nov 22 at 8:09













up vote
2
down vote

favorite









up vote
2
down vote

favorite











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>












share|improve this question















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>








  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>





  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>






javascript web-component lit-element






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 at 16:02

























asked Nov 21 at 10:14









Sirko

53.4k1598143




53.4k1598143












  • you could listen to the slotchange event
    – Supersharp
    Nov 22 at 0:04










  • @Supersharp Thanks! After some fiddling with the details (seems I need to attach the event to the shadowRoot and not the element itself), this worked. If you put that into an answer, I'll gladly accept it.
    – Sirko
    Nov 22 at 8:09


















  • you could listen to the slotchange event
    – Supersharp
    Nov 22 at 0:04










  • @Supersharp Thanks! After some fiddling with the details (seems I need to attach the event to the shadowRoot and not the element itself), this worked. If you put that into an answer, I'll gladly accept it.
    – Sirko
    Nov 22 at 8:09
















you could listen to the slotchange event
– Supersharp
Nov 22 at 0:04




you could listen to the slotchange event
– Supersharp
Nov 22 at 0:04












@Supersharp Thanks! After some fiddling with the details (seems I need to attach the event to the shadowRoot and not the element itself), this worked. If you put that into an answer, I'll gladly accept it.
– Sirko
Nov 22 at 8:09




@Supersharp Thanks! After some fiddling with the details (seems I need to attach the event to the shadowRoot and not the element itself), this worked. If you put that into an answer, I'll gladly accept it.
– Sirko
Nov 22 at 8:09












1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










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>








share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53409769%2flit-element-which-event-to-use-for-dom-updates%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    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>








    share|improve this answer



























      up vote
      2
      down vote



      accepted










      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>








      share|improve this answer

























        up vote
        2
        down vote



        accepted







        up vote
        2
        down vote



        accepted






        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>








        share|improve this answer














        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>








        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>





        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>






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 22 at 13:54

























        answered Nov 22 at 10:13









        Supersharp

        12.7k22767




        12.7k22767






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53409769%2flit-element-which-event-to-use-for-dom-updates%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            What visual should I use to simply compare current year value vs last year in Power BI desktop

            How to ignore python UserWarning in pytest?

            Alexandru Averescu