Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not able to use ApexCharts.js as web-component #1332

Closed
ulshv opened this issue Feb 25, 2020 · 7 comments · Fixed by #2750
Closed

Not able to use ApexCharts.js as web-component #1332

ulshv opened this issue Feb 25, 2020 · 7 comments · Fixed by #2750

Comments

@ulshv
Copy link

ulshv commented Feb 25, 2020

Great lib! Anyways, I'm not able to use it in new project which is based on web-components with LitElement. It's throwing this error:

DetectElementResize.js:79 Uncaught (in promise) TypeError: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
    at push../node_modules/apexcharts/src/utils/DetectElementResize.js.window.addResizeListener (DetectElementResize.js:79)
    at apexcharts.js:113
    at new Promise (<anonymous>)
    at ApexCharts.render (apexcharts.js:90)
    at HTMLElement.<anonymous> (hs-line-chart.ts:29)

Code example:

import { LitElement, html } from 'lit-element';
import ApexCharts from 'apexcharts';

class LineChart extends LitElement {
  static get is() {
    return 'line-chart';
  }

  async renderChart() {
    await this.updateComplete;

    var options = {
      theme: 'dark',
      chart: {
        type: 'line',
      },
      series: [{
        name: 'sales',
        data: [30,40,35,50,49,60,70,91,125]
      }],
      xaxis: {
        categories: [1991,1992,1993,1994,1995,1996,1997, 1998,1999]
      }
    }

    var chart = new ApexCharts(this.shadowRoot.querySelector("#container"), options);

    chart.render();
  }

  render() {
    return html`<div id="container"></div>`;
  }
}

window.customElements.define(LineChart.is, LineChart);

export default LineChart;
@ulshv
Copy link
Author

ulshv commented Feb 25, 2020

DocumentFragment is passed instead of HTMLElement object in getComputedStyle.
is there any workaround to fix it?

@ulshv
Copy link
Author

ulshv commented Feb 25, 2020

Ok, found the workaround. It basically disables shadow-root for custom element (using LitElement). Issue resolved.

class LineChart extends LitElement {
  // ...

  createRenderRoot() {
    return this;
  }

  async renderChart({ series, xaxis }) {
    await this.updateComplete;

    var options = { /* ... */ };

    const div = document.createElement('div');
    this.appendChild(div);

    var chart = new ApexCharts(div, options);

    chart.render();
  }

  render() {}
}

@ulshv ulshv closed this as completed Feb 25, 2020
@oneezy
Copy link

oneezy commented Feb 14, 2021

hi @ulshv , i've never worked with LitElement before but I have worked with Polymer a few years back. I heard the 2 are similar. Anyways, do you know how to take your code and use it within a vanilla js web component? It seems straight forward but I haven't gotten it to work. I was attempting to get your example above to work with LitElement first before I convert it into a a vanilla component but I can't even get that to work 😄

Do you know what I'm doing wrong?
https://codepen.io/oneezy/pen/jOVyePM

@dazraf
Copy link

dazraf commented Sep 2, 2021

Hi @ulshv thanks for creating this issue. I'm trying to do something similar with LitElement. Did you run into any issues with ApexCharts css not being loaded / accessed? Thanks.

@dazraf
Copy link

dazraf commented Sep 2, 2021

I was able to directly load the css within the render method.

 render() {
    return html`
      <link rel="stylesheet" type="text/css" href="./node_modules/apexcharts/dist/apexcharts.css">
      <div class="chart-container"></div>
      `;
  }

However, this approach is strongly not recommended by LitElement.

I also tried copying the entire css into the elements static styles = css... block, but this didn't work.

Hi @ulshv thanks for creating this issue. I'm trying to do something similar with LitElement. Did you run into any issues with ApexCharts css not being loaded / accessed? Thanks.

@LeaVerou
Copy link
Contributor

LeaVerou commented Nov 2, 2021

Ok, found the workaround. It basically disables shadow-root for custom element (using LitElement). Issue resolved.

class LineChart extends LitElement {
  // ...

  createRenderRoot() {
    return this;
  }

  async renderChart({ series, xaxis }) {
    await this.updateComplete;

    var options = { /* ... */ };

    const div = document.createElement('div');
    this.appendChild(div);

    var chart = new ApexCharts(div, options);

    chart.render();
  }

  render() {}
}

That is only a workaround if you don’t actually need the Shadow DOM.
Also, this is not LitElement specific, I'm having the same issue with an entirely VanillaJS component I‘m writing.
Here's a reduced testcase: https://codepen.io/leaverou/pen/WNEXzBe?editors=1010
I think the issue should be reopened.

@LeaVerou
Copy link
Contributor

LeaVerou commented Nov 2, 2021

Here's a workaround that enables Apex Charts to work in Shadow DOM (but reduces browser support to those that support ResizeObserver and WeakMap, unless polyfills/shims are used):

let ros = new WeakMap();

window.addResizeListener = function(el, fn) {
	let called = false;

	let ro = new ResizeObserver(r => {
		if (called) { // We don't want to call it immediately
			fn.call(el, r);
		}
		called = true;
	});

	if (el.nodeType === Node.DOCUMENT_FRAGMENT_NODE){
		// Observe children instead
		Array.from(el.children).forEach(c => ro.observe(c));
	}
	else {
		ro.observe(el);
	}

	ros.set(fn, ro);
};

window.removeResizeListener = function(el, fn) {
	let ro = ros.get(fn);
	if (ro) {
		ro.disconnect();
		ros.delete(fn);
	}
}

The code would need to run after Apex Charts are imported, to correctly override the addResizeListener() and removeResizeListener() that ship with it.

It's just something I put together right now, and has not been extensively tested, but it's a starting point.

(You'd still need to work around the CSS not being imported properly, see #238)

junedchhipa added a commit that referenced this issue Nov 6, 2021
Replace old DetectElementResize script with ResizeObserver, fixes #1332 and #2743
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants