xieziyu/ngx-echarts

Failed import NgxEchartsModule in a Standalone Component

s-triar opened this issue ยท 9 comments

I think this ngx-echarts v14 is still not support the standalone component feature.
the documentation does not provide how to import NgxEchartsModule in the standalone component.
I have imported NgxEchartsModule with forRoot in app.module.ts with the old bootstrap way.

if I import just NgxEchartsModule without root, appears error in echarts directive on the html tamplate.
if I import NgxEchartsModule with forRoot, appears error in imports section in @component.

@Component({
  selector: 'app-overview',
  templateUrl: './overview.component.html',
  styleUrls: ['./overview.component.scss'],
  standalone: true,
  imports: [
    CommonModule,
    RouterModule,
    FlexLayoutModule,
    MatCardModule,
    NgxEchartsModule
    // NgxEchartsModule.forRoot({
    //   echarts: () => import('echarts')
    // })
  ]
})
<div echarts [options]="options"  class="demo-chart"></div> <!-- errordirective echarts-->

I guess it would be better to abandon the forRoot pattern and try to use injection tokens to provide the echarts library.

I am trying like this anf still getting error but different error.

@Component({
  selector: 'app-omzet-chart',
  standalone: true,
  templateUrl: './omzet-chart.component.html',
  styleUrls: ['./omzet-chart.component.scss'],
  imports: [
    CommonModule,
    MatFormFieldModule,
    MatSelectModule,
    ReactiveFormsModule,
    NgxEchartsModule
  ],
  providers:[
    DatePipe,
    {provide: NGX_ECHARTS_CONFIG, useFactory: () => import('echarts')},
    
  ]
})

the error in console log is
ERROR Error: Uncaught (in promise): TypeError: Cannot destructure property 'init' of 'undefined' as it is undefined. TypeError: Cannot destructure property 'init' of 'undefined' as it is undefined.

I found the way to fix it.

I am trying from this https://stackoverflow.com/questions/63176047/typeerror-cannot-destructure-property-init-of-object-null-as-it-is-null-in

I import echart in app.module
import * as echarts from 'echarts';
then add module like this

NgxEchartsModule.forRoot({
      echarts: { init: echarts.init }
    
    }),

then in standalone component I just add the NgxEchartsModule in imports

is there anyone can import with standalone components ?

we can try this way. It's working fine for me


import * as echarts from 'echarts';
import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';

@Component({
  selector: 'bar-chart',
  template: `
    <div
      style="height: auto;"
      [id]="id"
      echarts
      [options]="chartOptions"
      [merge]="mergeOption"
      (chartInit)="chartOnInit($event)"
      (chartClick)="onClick($event)"
      (chartDblClick)="onChartDblClick($event)"
    ></div>
  `,
  standalone: true,
  imports: [NgxEchartsModule],
  providers:[{provide: NGX_ECHARTS_CONFIG, useFactory: () => ({echarts: echarts})}]
})

I am trying like this anf still getting error but different error.

@Component({
  ...
  providers:[
    DatePipe,
    {provide: NGX_ECHARTS_CONFIG, useFactory: () => import('echarts')},
    
  ]
})

the error in console log is ERROR Error: Uncaught (in promise): TypeError: Cannot destructure property 'init' of 'undefined' as it is undefined. TypeError: Cannot destructure property 'init' of 'undefined' as it is undefined.

In this example, the problem is the factory is returning the import directly instead of a config object. The correct statement would be:
{provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) },

However in any case I suggest useValue to prevent the lib from being imported more than once if children try to inject it:
{provide: NGX_ECHARTS_CONFIG, useValue: { echarts: () => import('echarts') } },
Perhaps the README should be updated to use this method instead @xieziyu

we can try this way. It's working fine for me

import * as echarts from 'echarts';
import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';

@Component({
  ...
  providers:[{provide: NGX_ECHARTS_CONFIG, useFactory: () => ({echarts: echarts})}]
})

By loading it this way, you lose the benefit of lazy-loading the library, so the entire package will be bundled with your component.

we can try this way. It's working fine for me


import * as echarts from 'echarts';
import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';

@Component({
  selector: 'bar-chart',
  template: `
    <div
      style="height: auto;"
      [id]="id"
      echarts
      [options]="chartOptions"
      [merge]="mergeOption"
      (chartInit)="chartOnInit($event)"
      (chartClick)="onClick($event)"
      (chartDblClick)="onChartDblClick($event)"
    ></div>
  `,
  standalone: true,
  imports: [NgxEchartsModule],
  providers:[{provide: NGX_ECHARTS_CONFIG, useFactory: () => ({echarts: echarts})}]
})

When I use this solution i have this error

Property 'chartOptions' does not exist on type

semla commented

iiuc this imports the whole bundle? how to only import used parts?