Search code examples
angulartypescriptngx-charts

ngx pie chart - unable to access input data inside labelFormatting


I'm failing to access my portfolio input property inside the labelFormatting method.

I need this portfolio data in order to calculate the sum, so as to format the label data into percentages.

The problem I'm facing is that the portfolio object is persistently undefined when called within the context of the labelFormatting. I'm assuming this happens because this method is called before the input property is ready, when the chart is first created.

Here is my component:

export class PortfolioPreviewCardComponent {
    @Input() portfolio!: IPortfolio;
    data = [...];

    // options
    showLegend = false;
    showLabels = true;
    isDoughnut = true;

    ...
    ...
    ...

    labelFormatting(name: string) { // this name will contain the name you defined in chartData[]
        const self: any = this; // this "this" will refer to the chart component
        const data: DataItem[] = self.series.filter((x: { name: string }) => x.name == name);
    
        // portfolio is undefined here
        const sum = this.portfolio.holdings.reduce((accumulator, item) => {
            return accumulator + item.total;
        }, 0);

        if(data.length > 0) {
            return (((data[0].value / sum) * 100).toFixed(2) + '%');
        } else {
            return name;
        }
    }
}

Here is the template:

<ngx-charts-pie-chart
        *ngIf="portfolio"
        scheme="cool"
        [results]="data"
        [legend]="showLegend"
        [labels]="showLabels"
        [doughnut]="isDoughnut"
        [labelFormatting]="labelFormatting"
        (select)="onSelect($event)"
        (activate)="onActivate($event)"
        (deactivate)="onDeactivate($event)"
>
</ngx-charts-pie-chart>

Solution

  • I mananged to find a solution where I explicitly set the labelFormatting function of the chart in the AfterViewInit hook, like so:

    @ViewChild('pieChart') pieChart!: PieChartComponent; // template chart reference
    ...
    ...
    
    ngAfterViewInit(): void {
        if (this.pieChart) {
            // used a chartManager service to deal with the labelFormatting logic
            this.pieChart.labelFormatting = (name: string) => this.chartManager.labelFormatting(name);
        }
    }