Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 component's "this" is undefined when executing callback function

I have a component which calls a service to fetch data from a RESTful endpoint. This service needs to be given a callback function to execute after fetching said data.

The issue is when I try use the callback function to append the data to the existing data in a component's variable, I get a EXCEPTION: TypeError: Cannot read property 'messages' of undefined. Why is this undefined?

TypeScript version: Version 1.8.10

Controller code:

import {Component} from '@angular/core' import {ApiService} from '...'  @Component({     ... }) export class MainComponent {      private messages: Array<any>;      constructor(private apiService: ApiService){}      getMessages(){         this.apiService.getMessages(gotMessages);     }      gotMessages(messagesFromApi){         messagesFromApi.forEach((m) => {             this.messages.push(m) // EXCEPTION: TypeError: Cannot read property 'messages' of undefined         })     } } 
like image 890
Michael Gradek Avatar asked Jul 07 '16 12:07

Michael Gradek


2 Answers

Use the Function.prototype.bind function:

getMessages() {     this.apiService.getMessages(this.gotMessages.bind(this)); } 

What happens here is that you pass the gotMessages as a callback, when that is being executed the scope is different and so the this is not what you expected.
The bind function returns a new function that is bound to the this you defined.

You can, of course, use an arrow function there as well:

getMessages() {     this.apiService.getMessages(messages => this.gotMessages(messages)); } 

I prefer the bind syntax, but it's up to you.

A third option so to bind the method to begin with:

export class MainComponent {     getMessages = () => {         ...     } } 

Or

export class MainComponent {     ...      constructor(private apiService: ApiService) {         this.getMessages = this.getMessages.bind(this);     }      getMessages(){         this.apiService.getMessages(gotMessages);     } } 
like image 185
Nitzan Tomer Avatar answered Sep 27 '22 19:09

Nitzan Tomer


Or you can do it like this

gotMessages(messagesFromApi){     let that = this // somebody uses self      messagesFromApi.forEach((m) => {         that.messages.push(m) // or self.messages.push(m) - if you used self     }) } 
like image 39
Michal Kliment Avatar answered Sep 27 '22 21:09

Michal Kliment