Подтвердить что ты не робот

Angular2 компонент "this" - undefined при выполнении функции обратного вызова

У меня есть компонент, который вызывает службу для извлечения данных из конечной точки RESTful. Эта услуга должна быть предоставлена ​​для функции обратного вызова после извлечения указанных данных.

Проблема заключается в том, что когда я пытаюсь использовать функцию обратного вызова для добавления данных к существующим данным в компонентной переменной, я получаю EXCEPTION: TypeError: Cannot read property 'messages' of undefined. Почему this undefined?

TypeScript версия: версия 1.8.10

Код контроллера:

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
        })
    }
}
4b9b3361

Ответ 1

Используйте функцию Function.prototype.bind:

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

Что происходит, так это то, что вы передаете gotMessages в качестве обратного вызова, когда это выполняется, область действия различна, поэтому this не то, что вы ожидали.
Функция bind возвращает новую функцию, привязанную к this, которую вы определили.

Вы можете, конечно, также использовать функцию толстой стрелки:

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

Я предпочитаю синтаксис bind, но это зависит от вас.

Третий вариант, чтобы связать метод для начала:

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

Ответ 2

Поскольку вы просто передаете ссылку функции в getMessages, у вас нет правильного контекста this.

Вы можете легко исправить это, используя лямбда, которая автоматически связывает правильный контекст this для использования внутри этой анонимной функции:

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

Ответ 3

Или вы можете сделать это так:

gotMessages(messagesFromApi){
    let that = this // somebody uses self 
    messagesFromApi.forEach((m) => {
        that.messages.push(m) // or self.messages.push(m) - if you used self
    })
}

Ответ 4

Пожалуйста, определите функцию

gotMessages = (messagesFromApi) => {
  messagesFromApi.forEach((m) => {
    this.messages.push(m)
  })
}