web-dev-qa-db-ja.com

コールバック関数を実行するとき、Angular2コンポーネントの「this」は未定義です

サービスを呼び出してRESTfulエンドポイントからデータを取得するコンポーネントがあります。このサービスには、上記のデータを取得した後に実行するコールバック関数を与える必要があります。

問題は、コールバック関数を使用してコンポーネントの変数内の既存のデータにデータを追加しようとすると、EXCEPTION: TypeError: Cannot read property 'messages' of undefinedが返されることです。 thisが未定義なのはなぜですか?

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
        })
    }
}
70
Michael Gradek

Function.prototype.bind 関数を使用します。

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

ここで何が起こるかは、gotMessagesをコールバックとして渡すことです。それが実行されているとき、スコープが異なるため、thisは期待したものではありません。
bind関数は、定義したthisにバインドされた新しい関数を返します。

もちろん、 矢印関数 も使用できます:

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

bind構文を好みますが、それはあなた次第です。

メソッドを次のようにバインドする3番目のオプション:

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

または

export class MainComponent {
    ...

    constructor(private apiService: ApiService) {
        this.getMessages = this.getMessages.bind(this);
    }

    getMessages(){
        this.apiService.getMessages(gotMessages);
    }
}
122
Nitzan Tomer

または、このようにすることができます

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

getMessagesの関数参照を渡すだけなので、正しいthisコンテキストがありません。

その匿名関数内で使用するために正しいthisコンテキストを自動的にバインドするラムダを使用することで、簡単に修正できます。

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

関数を定義してください

gotMessages = (messagesFromApi) => {
  messagesFromApi.forEach((m) => {
    this.messages.Push(m)
  })
}
0
Tài