I have researched other similar items here so far without result and obviously need to understand promises better but I am struggling here.
I have an Ionic 4/Angular 8 project with and Azure based back-end. I am trying to get the pages to display images from the Azure storage which requires a key appended to the url.
To avoid having the 'check key, get a new one if expired, append to url' code in every page, I thought I'd make a service function to do it. But though I can get it to work, the calling function doesn't appear to be waiting on the '.then' and so I am getting undefined. (I think). Ideally, I would like the service to just return a string
The service function (with some comments and debug o/p) I have is this:
// Ideally I'd like to just return a string here ---v
// v- but the async nature needs async return type ??
async getStorageURLWithKey(url: string): Promise<string> {
const nowplus5 = addMinutes(Date.now(), 5); // 5 mins to give some leeway
console.log(nowplus5);
console.log(url);
console.log(this.azurekey);
if (!this.azurekey || isBefore( this.azurekey.Expires, nowplus5 )) {
console.log('Getting new Key');
const keyObj = await this.getAzureKeyServer().toPromise();
await this.saveAzureKeyStore(keyObj);
return url + keyObj.Key; // Return the url with the new Key
} else {
console.log('Key is valid' + this.azurekey.Expires);
const rval = new Promise<string>(function(res) {
res(url + this.azurekey.Key);
});
return rval ; // Key is in time so return it with url
}
}
My calling function is this:
getBizImg(): string {
console.log('GetBizImg');
if (this.business.Id) { // We have a Business Object
this.userService.getStorageURLWithKey(this.business.ImageURL).then((url) => {
console.log(url);
return url;
}, reject => {
console.log('Rejected:' + reject);
});
} else {
return '';
}
}
If I call the getBizImg function from say ngOninit, it is getting back undefined before the getBizImg - console.log(url) line.
Here's the ngOninit:
ngOnInit() {
const imageurl = this.getBizImg();
console.log(imageurl);
}
Really the call should be coming from the page:
<ion-content padding>
<ion-img [src]="getBizImg()" ></ion-img>
</ion-content>
But i have commented this out till I can resolve this issue. Otherwise it gets into a seemingly endless loop.
If I turn the getBizImg() into an async function and await the call and return a promise, it works fine -if I modify my ngInit to:
ngOnInit() {
this.getBizImg().then((wibble) => {
console.log(wibble);
});
}
and the getBizImg function to:
async getBizImg(): Promise<string> {
console.log('GetBizImg ID= ' + this.business.Id);
if (this.business.Id) { // We have a Business Object
const url = await this.userService.getStorageURLWithKey(this.business.ImageURL);
console.log(url);
return url;
} else {
return '';
}
}
But that won't get me the simple string I need for the HTML.
I'm not sure if I am missing something (probably) obvious...
**** Edit update**** I have tried changing to the fully async and including the angular async pipe:
<ion-content padding>
BIZ IMAGE
<ion-img [src]="getBizImg() | async" ></ion-img>
I also tried to just show the string with:URL is: {{ getBizImg() | async }}
But it gets into a (seemingly endless loop). It is strange though, because it is getting to the this.getAzureKeyServer() function but I am not hitting a breakpoint that I have set in my server code at the GetKey API call.
This set me on a different path to check the page function some more. I took out the calls to the back end to just return a string like this:
<ion-content padding>
BIZ IMAGE
URL is: {{ getBizImg() | async }}
</ion-content>
async getBizImg(): Promise<string> {
console.log('GetBizImg ID= ' + this.business.Id);
if (this.business.Id) { // We have a Business Object
const url = 'wibble'; // this.business.ImageURL;
// const url = await this.userService.getStorageURLWithKey(this.business.ImageURL);
console.log(url);
return url;
} else {
console.log('invalid id');
return 'invalid id';
}
}
... and that just gets into an endless loop too, so I am thinking there is something more fundamental going on... I mean have I made some kind of schoolboy error here?