Reputation: 55
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
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
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