サービスを呼び出して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
})
}
}
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);
}
}
または、このようにすることができます
gotMessages(messagesFromApi){
let that = this // somebody uses self
messagesFromApi.forEach((m) => {
that.messages.Push(m) // or self.messages.Push(m) - if you used self
})
}
getMessages
の関数参照を渡すだけなので、正しいthis
コンテキストがありません。
その匿名関数内で使用するために正しいthis
コンテキストを自動的にバインドするラムダを使用することで、簡単に修正できます。
getMessages(){
this.apiService.getMessages((data) => this.gotMessages(data));
}
関数を定義してください
gotMessages = (messagesFromApi) => {
messagesFromApi.forEach((m) => {
this.messages.Push(m)
})
}