The this-variable is the Window object or undefined in the then-method of a promise

607 views Asked by At

In ES2015 (formerly ES6), I thought using the arrow syntax should lead the this variable to be the object you are in, making the old var that = this technique obsolete.

However, in my function for the then-part of a Promise, the this variable is the Window object (in Chrome) or undefined (in FF and IE11):

import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';

@inject(HttpClient)
export class InvoiceGenerator {
    items = [];

    constructor(http) {
        this.http = http;
    }

    activate() {
        this.http
            .get(`http://${window.location.host}/api/invoice`)
            .then(response => {
                this.something = response.someProperty; // this is the Window 
            }).catch(err => {
                console.log(err); 
            });
    }
}

I'm using Aurelia by the way, in case it is important.

How can I get the this variable to be the object I am currently in (my Aurelia viewmodel), without using the old var that = this technique?

2

There are 2 answers

0
Jordan Running On

You're correct that "the arrow syntax should lead the this variable to be the object you are in," but you're confused about what object you're "in." When you do this:

this.http
  .get(`http://${window.location.host}/api/invoice`)
  .then(response => {
    this.something = response.someProperty; // this is the Window object
  });

It's equivalent to this:

let thenFn = response => { this.something = response.someProperty; }

this.http
  .get(`http://${window.location.host}/api/invoice`)
  .then(thenFn);

Defining the function inside the parentheses (then(response => ...)) doesn't change the fact that you're defining it in the same context in which this.http exists—which in your case is apparently window.

Unfortunately I can't tell you how to make this refer to your Aurelia viewmodel because you haven't shown your viewmodel code or any other context.

0
Chi Row On

You need to declare 'something' property in your class before referring it with 'this' in the callback because the 'this' in callback does not contain 'something' property nor will it create it.

export class InvoiceGenerator {
    something = [];

    constructor(http) {
        this.http = http;
    }

    activate() {
        this.http
            .get(`http://${window.location.host}/api/invoice`)
            .then(response => {
                this.something = response.someProperty; // this is the Window 
            }).catch(err => {
            console.log(err); 
        });
    }
}

I have not tried it but I believe Typescript would have caught the error.