Saving typescript functions as object variables (Angular 6)

I'm trying to create a simple abstraction using Google charts, I've created a chartservice which will serve as the abstraction. The module supplies the options and data-source, and the service takes care of the rest(data is supplied by a REST API).

Here is the current code, works only for one case:

createCombo(comboBarLabels: String[], comboBarTypes: String[], options: any, element: any) {
    this.overviewService.getOverviewAggBarData().pipe(first()).subscribe(comboRequest => {
      for (const index of Object.keys(comboRequest.comboData)) {
        comboRequest.comboData[index].unshift(comboBarLabels[index]);
      }
      const data_array = [comboBarTypes, comboRequest.comboData[0],
        comboRequest.comboData[1], comboRequest.comboData[2]];
      google.charts.load('current', {'packages': ['corechart']});
      google.charts.setOnLoadCallback(() => {
        const data = ChartService.createDataTable(data_array);
        const chart = new google.visualization.ComboChart(element);
        chart.draw(data, options);
      });
    });
  }

What I want to achieve is to remove this.overviewService.getOverviewAggBarData() and replace it by a conditional function, something like this in python:

def foo(a, b):  # Adds two numbers
    return a + b
a = foo
print(a(1, 2))  # Prints 3

To make something that looks like this:

createCombo(comboBarLabels: String[], comboBarTypes: String[], options: any, element: any, source: any) {
  if (source == "OverviewAggBar"){
    get_data = this.overviewService.getOverviewAggBarData;
  } else {
    get_data = this.overviewService.getOverviewPieData;
  }
  get_data().pipe(first()).subscribe(comboRequest => {
    for (const index of Object.keys(comboRequest.comboData)) {
      comboRequest.comboData[index].unshift(comboBarLabels[index]);
    }
    const data_array = [comboBarTypes, comboRequest.comboData[0],
      comboRequest.comboData[1], comboRequest.comboData[2]];
    google.charts.load('current', {'packages': ['corechart']});
    google.charts.setOnLoadCallback(() => {
      const data = ChartService.createDataTable(data_array);
      const chart = new google.visualization.ComboChart(element);
      chart.draw(data, options);
    });
  });
}

The reason that I want to do this is because the function call is very involved, being able to abstract this part away paves the way for making an even more general function. Other solutions to achieve the same goal are more than welcome!

Solved, here's the new code:

createCombo(comboBarLabels: String[], comboBarTypes: String[], options: any, element: any, source: string) {
    let getData: any;
    if (source === 'getAggData') {
      getData = this.overviewService.getOverviewAggBarData.bind(this);
    } else {
      getData = this.overviewService.getOverviewPieData.bind(this);
    }
    getData().pipe(first()).subscribe(comboRequest => {
      const data_array = [comboBarTypes];
      for (const index of Object.keys(comboRequest.comboData)) {
        comboRequest.comboData[index].unshift(comboBarLabels[index]);
        data_array.push(comboRequest.comboData[index]);
      }
      google.charts.load('current', {'packages': ['corechart']});
      google.charts.setOnLoadCallback(() => {
        const data = ChartService.createDataTable(data_array);
        const chart = new google.visualization.ComboChart(element);
        chart.draw(data, options);
      });
    });
  }

2 answers

  • answered 2018-10-09 16:34 Khalid

    If I understand you correctly I think you’re already there. JavaScript (and TypeScript) allows the same kind of behavior. What is missing in your code is declaring get_data. I’d use a ternary operator to do that:

    const get_data = source === “OverviewAggBar” ? this.overviewService.getOverviewAggBarData : this.overviewService.getOverviewPieData;
    

  • answered 2018-10-09 17:02 Frank Modica

    If you will have many functions, you could create a "map" from the source string to function. Then you can just add more functions to the map. Something like this:

    class YourClass {
        private mapFromSourceToFunction: { [key: string]: () => Observable<YourComboResponseType> } = {
            'getAggData': () => this.overviewService.getOverviewAggBarData(),
            'getPipeData': () => this.overviewService.getOverviewPieData(),
            'getSomethingElse': () => this.overviewService.getSomethingElse()
        };
    
        createCombo(comboBarLabels: String[], comboBarTypes: String[], options: any, element: any, source: string) {
            let getData = this.mapFromSourceToFunction[source];
    
            // getData().pipe ...
        }
    }