0

I am trying to create a chart in angular and I get data using a service. I want to use the array data get from here. pieData: any = []; The console inside the constructor show the data correctly. but the console inside the ngOnInit shows empty array.

import { Component, OnInit } from '@angular/core';
import { PieChartService } from './pie-chart.service';
@Component({
  selector: 'app-pie-chart',
  templateUrl: './pie-chart.component.html',
  styleUrls: ['./pie-chart.component.css']
})
export class PieChartComponent implements OnInit {
  pieData: any = []; 

  constructor(private PieChart: PieChartService) {
    this.PieChart.getMethod().subscribe((res: any) => {
      this.pieData = res.pieData;
      console.log(this.pieData);
    })
  }
  ngOnInit() { }
 //code for create a graph here
}
  • You already have done it `this.pieData = res.pieData;`... just that it's inside a `subscription`. So, it may so be that when you want to use it at some other place, it may not be available... Then you will have to make adjustments in order to start using `this.pieData`... – Nalin Ranjan Mar 03 '22 at 06:05
  • One more thing, why don't you move that call to fetch data inside `OnInit` instead of constructor? – Nalin Ranjan Mar 03 '22 at 06:06
  • but when i call console.log(this.pieData); inside the ngOnInit shows empty array –  Mar 03 '22 at 06:08
  • I want to use this pieData for another implementation on ts file. but the data do not work properly –  Mar 03 '22 at 06:11
  • It's empty because it is getting set inside an Observer. When that subscription finishes then only you will have data. But console.log is executing while there is a request getting data for you. – Nalin Ranjan Mar 03 '22 at 06:33
  • If you want to wait for that request to finish and then continue execution, then convert this observable into a `Promise` and put an `await` before ... – Nalin Ranjan Mar 03 '22 at 06:35
  • I have no idea about that. can you please help sir –  Mar 03 '22 at 06:44

2 Answers2

1

What you can try is to move the subscription inside the ngOnInit hook, so that you can write your code or call the function for creating the chart from inside the subscription. Though I am not sure why would you need the subscription inside the constructor but I would say that it is not a best practice to do work inside the constructor as it is mostly used for initalizing class members. Whereas ngOnInit is called after all data bound properties of your component has been intialized.

Also quoting Difference between ngOnInit and constructor

Mostly we use ngOnInit for all the initialization/declaration and avoid stuff to work in the constructor. The constructor should only be used to initialize class members but shouldn't do actual "work".

So you should use constructor() to setup Dependency Injection and not much else. ngOnInit() is better place to "start" - it's where/when components' bindings are resolved.

The solution to your problem would be:

pieData$: Subscription; // subscription for data
ngOnInit() { 
  this.pieData$ = this.PieChart.getMethod().subscribe((res: any) => {
    this.pieData = res.pieData;
    console.log(this.pieData);
    //code for create a graph here
  })
}

Also don't forget to unsubscribe to the subscription on Destroy

ngOnDestroy() {
  this.pieData$.unsubscribe();
}
jayant0jha
  • 71
  • 6
  • one more thing, when we get data using input from another component, How can I do it? –  Mar 04 '22 at 11:02
  • If you're getting data using the input decorator, your components will be following a parent child relationship, you'll always find data in the OnInit lifecycle hook if you're passing it from the parent to the child. You can listen for changes in the data, in the ngOnChanges hook, though I would advice not to use that as that fires with every change detection cycle, so that can cause performance issues, so avoid that unless you need it. You can read more about lifecycle hooks in angular docs. https://angular.io/guide/lifecycle-hooks – jayant0jha Mar 04 '22 at 19:18
0

Alternative: Using a Promise

pie-component.ts

import { Component, OnInit } from '@angular/core';
import { PieChartService } from './pie-chart.service';

@Component({
    selector: 'app-pie-chart',
    templateUrl: './pie-chart.component.html',
    styleUrls: ['./pie-chart.component.css'],
})
export class PieChartComponent implements OnInit {
    pieData: any = [];

    constructor(private PieChart: PieChartService) {
        console.log('[PieChartComponent]', '[constructor]');
    }

    async ngOnInit() {
        console.log('[PieChartComponent]', '[OnInit]');
        // Follwoing promise is `await`-ed, so execution proceeds once that finishes,
        // and after which this.pieData will be set and can be accessed for values 
        // from anywhere else in the component's lifecycle hooks or any other operations 
        // that it supports. Enclose within a try-catch for error handling
        const pieDataResponse = await this.PieChart.getMethod().toPromise();
        this.pieData = pieDataResponse?.pieData || [];
        console.log('[PieChartComponent]', '[pieData]', '[Received]', this.pieData);
        //code for create a graph here
    }
}

WYSIWYG => WHAT YOU SHOW IS WHAT YOU GET

Nalin Ranjan
  • 1,728
  • 2
  • 9
  • 10