Tiehscher
Tiehscher

Reputation: 55

Aurelia with Typescript and async functions: this is undefined

I'm using typescript with aurelia and I think I can't find a way to put a variable into the right scope.

// detail.ts
import {autoinject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';
import {pApi} from './resources/services/APIService';

let http = new HttpClient();
let httpApi = new pApi(http);

@autoinject
export  class PatDetail {

    newDialog(patId, cat) {
    let burl: string = 'bar/foo/list/';
    const eurl: string = 'foo/bar/list/' + patId + '/';
    let result: string[] = httpApi.getLists(eurl, burl);
    }
}

This is the Apiservice-file:

// APIService.ts
import {autoinject} from 'aurelia-framework';
import {HttpClient, json} from 'aurelia-fetch-client';

@autoinject
export class pApi {
    constructor(private http: HttpClient) {
        http.configure(config => {
            config
                .useStandardConfiguration()
                .withBaseUrl('http://localhost:8000/')
        });
    }

getLists(eurl, burl) {
    async function getQuote() {
        await this.http.fetch(eurl)
        .then(resp => resp.json())
        .then(data => {
            console.log(data)
            return data
        })
        .catch(error => console.log(error))
    }


    async function getBlock() {
        await this.http.fetch(burl)
        .then(resp => resp.json())
        .then(data => {
            console.log(data)
            return data
        })
        .catch(error => console.log(error))
    }

    async function getBoth() {
        return await Promise.all([getBlock])
    }

    getBoth().then(results => {
        console.log(results)
        return results
    });
}

Running this throws the error:

Unhandled rejection TypeError: this is undefined

Actually I want to run to independent Promises at the same time and put them into a viewModel. Maybe I could also run it as ordinary Promise-call. But I thought the rather new async/await call would fit for this solution.

So far I couldn't find any fitting solutions / explanations for my problem. Since I'm new to Typescript and Aurelia I'm stucked. Thank you for your explanations why this error happens or better approaches.

Upvotes: 2

Views: 973

Answers (2)

Fred Kleuver
Fred Kleuver

Reputation: 8047

EDIT: rewrote my answer a bit

Donovan is right in his answer that you need to use arrow functions instead of regular functions due to the scoping issue, but I would go a step further and say you probably shouldn't inline them like that.

Async is kind of meant to get rid of the then soup. If you're using async, best fully utilize it. You would rewrite your method like this:

async getLists(eurl, burl) {
    const results = await Promise.all([
        this.getQuote(eurl),
        this.getBlock(burl)
    ]);

    console.log(results);
    return results;
}


async getQuote(eurl) {
    try {
        const resp = await this.http.fetch(eurl);
        const data = await resp.json();
        console.log(data);
        return data;
    } catch (error) {
        console.log(error);
    }
}

async getBlock(burl) {
    try {
        const resp = await this.http.fetch(burl);
        const data = await resp.json();
        console.log(data);
        return data;
    } catch (error) {
        console.log(error);
    }
}

Or to stick to your method, go non-async and simply put the unresolved promises in an array which you can then .all at the end:

getLists(eurl, burl) {
    const block = this.http
        .fetch(eurl)
        .then(resp => resp.json())
        .then(data => {
            console.log(data);
            return data;
        })
        .catch(error => console.log(error));

    const quote = this.http
        .fetch(burl)
        .then(resp => resp.json())
        .then(data => {
            console.log(data);
            return data;
        })
        .catch(error => console.log(error));

    return Promise.all([block, quote])
        .then(results => {
            console.log(results);
            return results;
        });
}

But mixing them = maintenance hell :)

Upvotes: 3

Donovan Woodside
Donovan Woodside

Reputation: 1911

This:

async function getQuote() {
    await this.http.fetch(eurl)
        .then(resp => resp.json())
        .then(data => {
            console.log(data)
            return data
        })
        .catch(error => console.log(error))
}

Should be this (lose the "function" keyword):

async getQuote() {
    await this.http.fetch(eurl)
        .then(resp => resp.json())
        .then(data => {
            console.log(data)
            return data
        })
        .catch(error => console.log(error))
}

With the use of "function" keyword you lose the context to the current object and "this" becomes local within the function alone.

Upvotes: 0

Related Questions