Home > Software design >  Angular chart not showing until i resize window after routing implementation
Angular chart not showing until i resize window after routing implementation

Time:01-14

Hello i cant figure out why my chart is not showing after i implemented routing. I have 3 tabs and without routing it was working just fine and after i added routing to each tab the graph is not showing until i resize window I am using primeng chart which uses chart.js library. https://www.primefaces.org/primeng/chart/line

here is chart ts

export class ChartComponent implements OnInit, OnDestroy {
  showError: string;
  basicData: { labels: string[]; datasets: Dataset[] } = {
    labels: [],
    datasets: [],
  };
  private componentDestroyed$: Subject<boolean> = new Subject();
  weatherDataLoading: boolean;

  constructor(
    private weatherService: WeatherService,
    public datePipe: DatePipe
  ) {}

  ngOnInit(): void {
    this.weatherDataLoading = true;
    this.weatherService
      .getWeatherDataForChart()
      .pipe(
        finalize(() => (this.weatherDataLoading = false)),
        takeUntil(this.componentDestroyed$)
      )
      .subscribe({
        next: (data) => {
          this.basicData.labels = data.labels.map((time) =>
            this.datePipe.transform(time, 'shortTime')
          );
          this.basicData.datasets = data.datasets;
        },
        error: () =>
          (this.showError =
            'Something went wrong. Please try refreshing the page'),
      });
  }

  ngOnDestroy(): void {
    this.componentDestroyed$.next(true);
    this.componentDestroyed$.complete();
  }
}

here is chart html

<div  >
  <div *ngIf="weatherDataLoading" >
    <div ></div>
  </div>
  <p-chart type="line" height="80vh" [data]="basicData"></p-chart>
</div>

and service function

getWeatherDataForChart(): Observable<{
    labels: string[];
    datasets: Dataset[];
  }> {
    return this.getWeatherData().pipe(
      map((historicalWeatherData) => {
        const data = historicalWeatherData.hourly.temperature_2m.map(
          (value, i) => {
            return {
              temperature: value,
              time: historicalWeatherData.hourly.time[i],
            };
          }
        );
        const labels = data.map((item) => item.time);
        const datasets = [
          new Dataset(
            'Temperature',
            data.map((item) => item.temperature),
            false,
            '#42A5F5',
            0.4
          ),
        ];
        return { labels, datasets };
      })
    );
  }

the getWeatherData function just get raw data from api.

chart module for routing :

const routes: Routes = [{ path: '', component: ChartComponent }];

@NgModule({
  declarations: [],
  imports: [CommonModule, RouterModule.forChild(routes)],
})
export class ChartModule {}

app routing:

const appRoutes: Routes = [
  {
    path: '',
    redirectTo: '/weather-data',
    pathMatch: 'full',
  },
  {
    path: 'weather-data',
    loadChildren: () =>
      import('./modules/weather-data.module').then((m) => m.WeatherDataModule),
  },
  {
    path: 'chart',
    loadChildren: () =>
      import('./modules/chart.module').then((m) => m.ChartModule),
  },
  {
    path: 'heat-index',
    loadChildren: () =>
      import('./modules/heat-index.module').then((m) => m.HeatIndexModule),
  },
  {
    path: '**',
    component: PageNotFoundComponent,
  },
];

@NgModule({
  declarations: [],
  imports: [CommonModule, RouterModule.forRoot(appRoutes)],
})
export class AppRoutingModule {}

I know when i move the datasets, labels manipulation which is in service to component subscription it then works or if i just assign the data to basicData in the subscription like this it works but then i dont know how would i transform the date to my desired format ?

.subscribe({
        next: (data) => {
          this.basicData = data
// this works but how to format the date now ?

but i would like to know if its possible to make it work when the manipulation is done in service.

i tried using ngAfterViewInit instead of ngOnInit or setTimeout() in the subscription but no luck. i have to resize the window even tiny bit and the chart show up. also tried to initialize basicData in ngOnInit or constructor

CodePudding user response:

Angular initialise components and variable, it track changes for those variables for deep equality. And when using array it has the same memory location, that does not trigger the change in the same cycle.

In change detection cycle one let say, it initialise with empty

basicData: { labels: string[]; datasets: Dataset[] } = {
    labels: [],
    datasets: [],
  };

ngOnInit basically adding these data but does not triggering the Angular change detection.

To trigger this detection simply, create new array or somehow assign a new memory to those variables.

try this your subscriptions, once you get the value.

      const labels = data.labels.map((time) =>
        this.datePipe.transform(time, 'shortTime')
      );
      this.basicData = {labels: [...labels], dataset:[...data.datasets]}

That is the reason it was working, when you do this in subscription.

  • Related