Search code examples
angulartypescriptcallbackgoogle-visualizationtreemap

How to access Angular component property from a Google Charts callback


Using angular-google-charts (Angular 13.2), I need to create a TreeMap with a custom tooltip. The GoogleChartComponent has an options property named generateTooltip that takes a callback function. From that function, I need to access data that is a property of the Angular component (chart.data) that contains the GoogleChartComponent. But I can't access the component's property from within the callback function. The examples on Google's website are understandably straight JavaScript.

<!-- dashboard.component.html -->
<google-chart
  [data]="chart.data"
  [options]="chart.options"
  [title]="chart.title"
  [type]="chart.type"
  [columns]="chart.columns"
  [height]="chart.height"
  style="width: 100%"
></google-chart>
// dashboard.component.ts
import { Component, OnInit } from '@angular/core'
import { ChartType} from 'angular-google-charts'

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
  public chart = {
    title: '',
    type: ChartType.TreeMap,
    data: [
      ['Global', null, 0, 0, 'Global'],
      ['Americas', 'Global', 0, 0, 'Global'],
      ['EMEA', 'Global', 0, 0, 'Global'],
      ['Acme - Lab 1YR (New)', 'Americas', 326000, 100, 'Susan Moore'],
      ['Flexa - DevOps 1YR (New)', 'Americas', 206000, 0, 'Jeremy Young'],
      ['Organo - CI/CD 1YR (New)', 'EMEA', 188000, 0, 'Sif Nilsen'],
      ['Ny Carlsberg Glyptotek - Automated Test Lab 300 devices 1YR (New)', 'EMEA', 212000, 0, 'Nils Peter Bjørnsen'],
      ['Dunder Mifflin - SCM 2YR (New)', 'Americas', 448000, 50, 'Justin Case']
    ],
    columns: [
      {type: 'string', label: 'Opportunity', role: 'domain'},
      {type: 'string', label: 'Parent', role: 'data'},
      {type: 'number', label: 'Amount', role: 'tooltip'},
      {type: 'number', label: 'Score', role: 'data'},
      {type: 'string', label: 'Owner', role: 'tooltip'}
    ],
    options: {
      minColor: '#f00',
      midColor: '#ddd',
      maxColor: '#0d0',
      headerHeight: 0,
      fontFamily: 'Nunito',
      fontSize: 13,
      fontColor: 'black',
      generateTooltip: this._showFullTooltip
    },
    height: 290,
  }

  constructor () {
  }

  _showFullTooltip(row: number, size: number, value: number) {
    // This is where I need to get values out of this.chart.data[row]
    const amount = size.toLocaleString('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });
    const tooltip = `<div style="color:#fff; background:#313A4B; padding: 10px; border-width:1px; border-style: solid; border-color:#fff;">${amount}</div>`
    return tooltip;
  }

}

In the example above, one of the parameters passed to the callback is row. I need to get this.chart.data[row]. This doesn't work. I am thinking it's because the callback function works outside of Angular but I'm not sure what is the best way to connect the _showFullTooltip() function to component properties.

Any recommendations?


Solution

  • This is not an Angular issue, rather JS scoping. Instead of assigning generateTooltip: this._showFullTooltip, bind the scope to the function as well like so generateTooltip: this._showFullTooltip.bind(this).

    When you pass along a function reference the this keyword will be the context of whoever/whatever is invoking that function. By using the .bind(this) you overwrite the function invocation context with the current assignee context (DashboardComponent). This should allow you to use this.chart.data[row] in your _showFullTooltip function.