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












3















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




















  • 1





    you could listen to the slotchange event

    – Supersharp
    Nov 22 '18 at 0:04






  • 1





    @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 '18 at 8:09
















3















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




















  • 1





    you could listen to the slotchange event

    – Supersharp
    Nov 22 '18 at 0:04






  • 1





    @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 '18 at 8:09














3












3








3








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 '18 at 16:02







Sirko

















asked Nov 21 '18 at 10:14









SirkoSirko

54.4k15101144




54.4k15101144








  • 1





    you could listen to the slotchange event

    – Supersharp
    Nov 22 '18 at 0:04






  • 1





    @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 '18 at 8:09














  • 1





    you could listen to the slotchange event

    – Supersharp
    Nov 22 '18 at 0:04






  • 1





    @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 '18 at 8:09








1




1





you could listen to the slotchange event

– Supersharp
Nov 22 '18 at 0:04





you could listen to the slotchange event

– Supersharp
Nov 22 '18 at 0:04




1




1





@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 '18 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 '18 at 8:09












1 Answer
1






active

oldest

votes


















3














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',
    autoActivateHeartbeat: false,
    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









    3














    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






























      3














      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




























        3












        3








        3







        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 '18 at 13:54

























        answered Nov 22 '18 at 10:13









        SupersharpSupersharp

        14k22971




        14k22971
































            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.




            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

            "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

            Alcedinidae

            Origin of the phrase “under your belt”?