highcharts / highcharts-angular

Highcharts official integration for Angular
Other
427 stars 117 forks source link

Angular Universal with highcharts-angular Getting Console Error when i run the project using dev:ssr and build:ssr ERROR TypeError: this.Highcharts[(this.constructorType || "chart")] is not a function #216

Open karthikeyansgit opened 3 years ago

karthikeyansgit commented 3 years ago

I have created simple angular universal (@nguniversal/express-engine) application and simple 'highcharts-angular' in app.component.

While running this project using 'ng serve' I am not getting any error in browser and node console.

When I run the project using "dev:ssr" or "build:ssr && serve:ssr" getting below error.

ERROR TypeError: this.Highcharts[(this.constructorType || "chart")] is not a function
    at HighchartsChartComponent.updateOrCreateChart (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:144647:74)
    at HighchartsChartComponent.wrappedUpdateOrCreateChart (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:144639:18)
    at HighchartsChartComponent.ngOnChanges (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:144626:18)
    at HighchartsChartComponent.wrapOnChangesHook_inPreviousChangesStorage (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:73368:18)
    at callHook (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:52549:14)
    at callHooks (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:52509:17)
    at executeInitAndCheckHooks (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:52449:9)
    at refreshView (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:58951:21)
    at refreshComponent (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:60383:13)
    at refreshChildComponents (C:\UnivHighCharts\dist\UnivHighCharts\server\main.js:58654:9)

I didn't find any jsfiddle to demo the code. Below github repo my code is available.

https://github.com/karthikeyansgit/UnivHighCharts

Anyone please suggest me how to fix this issue.

mateuszkornecki commented 3 years ago

You can find a detailed explanation below:

Code in index.js runs at twice. First run is done in an environment that lacks window (server side) and causes Highcharts to be loaded, but not initialized - see first few lines of code: http://code.highcharts.com/6.2.0/highcharts.src.js (it's a link to version 6.2.0 because that version is used in your demo project, but it's not different in current v7.0.0).

Easy fix is to place all modules inits in a if checking if Highcharts is an object or a function. It should be an object for modules initialization to work without any errors, so code like below is an easy fix:

if (typeof Highcharts === 'object') {
    HC_More(Highcharts)
}

After a file save the project is rebuild, but imported libraries are not reloaded. Because of this if you will change Highcharts instance (e.g. through a module initialization) and save the index.js file with those changes removed they will stay. The code run on environment without window defined runs once, so after index.js file saves you are safe - this should explain why saving helped.

The error is not about this repository's React wrapper for Highcharts - it's about loading Highcharts in an environment where it cannot be build because it requires browser environment with window and other related features. This is a know issue with NextJS and is covered here: https://github.com/zeit/next.js/wiki/FAQ#i-use-a-library-which-throws-window-is-undefined

Originally posted by @KacperMadej in https://github.com/highcharts/highcharts-react/issues/76#issuecomment-446408078

Since its a common question if think that we should mention about it in the highcharts-angular docs.

karthikeyansgit commented 3 years ago

@mateuszkornecki I try with the approach mentioned in your comment. But still I am getting error in node console. I tried all the solution mentioned in "highcharts-react" its now working for "highcharts-angular".

Is there any other solution available for Angular Universal approach please help me on this.

mateuszkornecki commented 3 years ago

I cloned your repository. It seems that the fix that I suggested previously won't be that straightforward that I thought. I will try to fix that from the wrapper level in the upcoming release. But till then to fix the problem you need to add a simple condition that will check if the code is running on the browser or not (or simply check if the typeof Highchart === 'object' ) and then prevent highcharts-chart component from rendering while running on the server-side.

export class AppComponent implements OnInit {
  isHighcharts = typeof Highcharts === 'object';
  title = 'UnivHighCharts';
  Highcharts: typeof Highcharts = Highcharts;
  chartConstructor: string = 'chart';
  chartOptions: Highcharts.Options = {};

  ngOnInit() {
    this.chartOptions = {
      series: [{
        data: [1, 2, 3],
        type: 'line'
      }]
    };
  }
}
<highcharts-chart
  *ngIf="isHighcharts"
  [Highcharts]="Highcharts"
  [constructorType]="chartConstructor"
  [options]="chartOptions"
  style="width: 100%; height: 400px; display: block;"
></highcharts-chart>
karthikeyansgit commented 3 years ago

@mateuszkornecki thanks for your update. Above solution works for in Angular Universal application.