"this" ขององค์ประกอบ Angular2 ไม่ได้กำหนดไว้เมื่อเรียกใช้ฟังก์ชันเรียกกลับ


94

ฉันมีส่วนประกอบที่เรียกใช้บริการเพื่อดึงข้อมูลจากจุดสิ้นสุด 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
        })
    }
}

คุณใช้ TypeScript เวอร์ชันใด (คุณสามารถตรวจสอบได้ด้วยtsc -v)
rinukkusu

ข้อยกเว้นเนื่องจาก forEach ใช้ For-of แทน
Pax Beach

คำตอบ:


159

ใช้ฟังก์ชัน Function.prototype.bind :

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

สิ่งที่เกิดขึ้นที่นี่คือคุณส่งผ่านgotMessagesเป็นการโทรกลับเมื่อมีการดำเนินการขอบเขตจะแตกต่างกันดังนั้นจึงthisไม่ใช่สิ่งที่คุณคาดหวัง ฟังก์ชันส่งกลับฟังก์ชั่นใหม่ที่ถูกผูกไว้กับคุณกำหนดไว้
bindthis

แน่นอนคุณสามารถใช้ฟังก์ชันลูกศรได้เช่นกัน:

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

ฉันชอบbindไวยากรณ์ แต่ขึ้นอยู่กับคุณ

ตัวเลือกที่สามเพื่อผูกวิธีการเริ่มต้นด้วย:

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

หรือ

export class MainComponent {
    ...

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

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

1
ทำงานแล้วขอบคุณ! และขอขอบคุณที่อธิบายว่าเหตุใดจึงเกิดขึ้น
Michael Gradek

ขอบคุณ! ความจริงที่ว่าสไตล์ OOP รั่วไหลเฉพาะจาวาสคริปต์ (ผูก) เป็นเรื่องน่าเศร้า
skfd


13

เนื่องจากคุณเพิ่งส่งการอ้างอิงฟังก์ชันโดยที่getMessagesคุณไม่มีthisบริบทที่ถูกต้อง

คุณสามารถแก้ไขได้อย่างง่ายดายโดยใช้แลมบ์ดาซึ่งเชื่อมโยงthisบริบทที่ถูกต้องโดยอัตโนมัติสำหรับการใช้งานภายในฟังก์ชันที่ไม่ระบุชื่อนั้น:

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

นั่นมัน! ขอบคุณ
Michael Gradek

สมบูรณ์แบบ. โซลูชันที่ง่ายและมีประสิทธิภาพ
คอน

1

ฉันมีปัญหาเดียวกันแก้ไขโดยใช้() => {} แทนฟังก์ชัน ()


สิ่งนี้ไม่ได้เพิ่มข้อมูลใด ๆ ในคำตอบที่มีอยู่
DerMike

0

โปรดกำหนดฟังก์ชัน

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

สิ่งนี้ไม่ได้เพิ่มข้อมูลใด ๆ ในคำตอบที่มีอยู่
DerMike
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.