13

If I have an Angular 2 component and I get data from a service that returns an async promise or observable how can I then call a method in the component to display that data?

@Component({
  moduleId: module.id,
  selector: 'charts',
  templateUrl: 'charts.component.html',
  providers: [DataService]
})
export class ChartsComponent implements OnInit {

  constructor(private dataService:DataService)

  ngOnInit() {
    this.getData();
  }

  getData(){
    this.dataService.getData().then(function (data) {
      this.drawChart(data);
    });
  }

  drawChart(){
     //implement drawing chart
  }
}

The problem is that inside a promise "this" in "this.drawChart()" no longer refers to the ChartsComponent class. How can I call a class method post promise?

Also, I cant put drawChart() inside the promise because it needs to use other class properties.

Quinma
  • 1,436
  • 2
  • 17
  • 39

2 Answers2

24

When you use Arrow functions, the this is kept:

getData(){
  this.dataService.getData().then((data) => { // <-- changed here
    this.drawChart(data);
  });
}
acdcjunior
  • 132,397
  • 37
  • 331
  • 304
  • 1
    Thank you! you saved me much head banging on a wall. – Quinma Aug 03 '16 at 23:15
  • This works well, although leaves a syntax error in my IDE, time to upgrade tools. – Paul Apr 11 '18 at 14:35
  • 1
    @Paul Arrow functions are a new syntax, available at ES6 version of JS. Your IDE probably supports it, but it may require configuration. – acdcjunior Apr 11 '18 at 14:37
  • @acdcjunior it appears this fails in IE11 - I initially tested in chrome – Paul Apr 11 '18 at 15:50
  • 1
    @Paul Yes, IE11 doesn't support it. You have to transpile it using babel or other. If you need it for IE11 and can't transpile, I suggest something like `this.dataService.getData().then(function (data) { this.drawChart(data); }.bind(this));` – acdcjunior Apr 11 '18 at 15:51
5

There are 2 solutions:

1) using "self":

     var self = this;
     ngOnInit() {
        self.getData();
     }

     getData(){
        self.dataService.getData().then(function (data) {
        self.drawChart(data);
     });

}

2) using "bind method" (or something like that):

.then(function (data) {
        this.drawChart(data);
     }).bind(this)

you can find so much information about this method, for example: Use of the JavaScript 'bind' method

I prefer first solution, because it helps make code more transparent.

Community
  • 1
  • 1
SirCapy
  • 295
  • 1
  • 12