Search code examples
web-componentshadow-dom

How to get the object created by customElement in a Web Component?


I am building a Web Component to be used in a Framework, which embeds a grid libary.

I have managed to get the grid to display by wrapping it in an HTMLElement Class

export default class DataGrid extends HTMLElement {    

    constructor() {
        super(); 

        let tmpl = document.createElement('template');
        tmpl.innerHTML = `
            <div id="lib-datagrid"></div>
        `;

        this._shadowRoot = this.attachShadow({mode: "open"});
        this._shadowRoot.appendChild(tmpl.content.cloneNode(true));

        this._rowData = [];

        ...
}

and

    // Load the grid
    customElements.define('my-grid', DataGrid);     

I need to be able to pass data into the Grid via a DataGrid instance. However it seems that createElements.define() takes a Class rather than an object instance, so I don't have the option to create an Instance (new DataGrid()) and pass that in.

My theory is that I should be able to retrieve the created element via the dom tree, but my Web Component lives within a Shadow Dom and my Web Component isn't itself a Dom element (I think) i.e. no "this.getRootNode()" etc, but do have access to document and window.

enter image description here

Am I missing something in the createElement process or is there a way to find the root node of the current shadow dom?

** Edit - adding Top level WebComponent view

export default (state) => {
const { items, alert, loading } = state;
return (
    <div>       
        <div className="card-top">
            <my-grid></my-grid>
        </div>
    </div>
);

};

** Edit 2

I have found that coding the class extends HTMLElement in-line (rather than in a seperate js file) does allow me to update a reference from the objects connectedCallback() function.

    let myobject = null;
    
    customElements.define('my-grid2', class extends HTMLElement {
        connectedCallback() {
          const shadow = this.attachShadow({mode: 'open'});
          shadow.innerHTML = `<p>
            Hello
          </p>`;

          myobject = this;
        }
      });  
    

Pending other suggestions - I will work with this and post an answer if it works out.


Solution

  • I have found a way to do this.

    By defining the HTMLElement class in-line and handling the grid wrapper object in the connectedCallback() function, I can get access to references for both the element created and the DataGrid wrapper object.

    All the DataGrid wrapper requires is the shadowRoot created as a constructor parameter.

    let myElement = null;
    let myDataGrid = null;
    
    // Load the grid
    customElements.define('my-grid', class extends HTMLElement {
        connectedCallback() {
    
            let tmpl = document.createElement('template');
            tmpl.innerHTML = `
                <div id="lib-datagrid"></div>
            `;
    
            const shadow = this.attachShadow({mode: 'open'});
            shadow.appendChild(tmpl.content.cloneNode(true));
    
            myDataGrid = new DataGrid(shadow);
            myElement = this;
        }
      });    
        
    

    With that I can now, later on, call a function on the DataGrid object to update data.