Search code examples
elmcustom-element

ELM Custom Elements


I have the following ELM view element:

Html.node "test-elem" 
 [ Attributes.attribute "data-count" (model.count |> String.fromInt) ]
 []

test-elem is a custom html element:

 constructor() {
        super();
        this.me = this;
    }
    connectedCallback() {
        console.info(this.dataset.count);
        this.div = document.createElement("div");
        this.appendChild(this.div);
        this.div.innerText = "" + this.dataset.count;
    }

   attributeChangedCallback() {
        console.info(this.dataset.count);

        this.div.innerText = "" + this.dataset.count;
    }

If model.count changes the custom element does not get regenerated. How do I force this?

https://ellie-app.com/6SRrZjCzwfra1

Edited with suggestions from @Robin, but no luck.


Solution

  • I don't see any problems with your Elm code, I think this is a problem with your custom element definition in JavaScript.

    I'm not familiar with the custom elements API, but looking at your code (reproduced below):

    customElements.define('test-elem', class TestElem extends HTMLElement {
    
            constructor() {
                super();
                this.me = this;
            }
            connectedCallback() {
                console.info(this.dataset.count);
                var div = document.createElement("div");
                this.appendChild(div);
                div.innerText = "" + this.dataset.count;
            }
        });
    

    and the MDN documentation for custom elements, it's apparent that you should change the connectedCallback method to attributeChangedCallback. The reason being that Elm uses a virtual DOM and makes the fewest actual DOM updates possible when your model changes. In particular, when the count changes it won't remove the custom element from the DOM and add a new one, it will just change the appropriate attribute. It seems that your connecedCallback won't therefore be called, but attributeChangedCallback should be.

    Also, as @Murdock correctly observed (by reading the MDN article, specifically the "Using the lifecycle callbacks" section, better than me), the data-count attribute has to be explicitly set to be observed, by using the observedAttributes getter, as follows:

    static get observedAttributes() {
        return ['data-count'];
    }