0

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?

1

2 Answers 2

1

getBizImg() never returns a URL since you only return it in the callback of the getStorageURLWithKey() promise.

Return that promise (and change the method type to Promise<string> and use the async pipe to display it:

getBizImg(): string {
  console.log('GetBizImg');
  if (this.business.Id) {  // We have a Business Object
    // return here
    return this.userService.getStorageURLWithKey(this.business.ImageURL).then((url) => {
      console.log(url);
      return url;
    }, reject => {
      console.log('Rejected:' + reject);
    });
  } else {
    return '';
  }
}
<ion-content padding>
   <ion-img [src]="getBizImg() | async"></ion-img>
</ion-content>
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Thomas, I have put an Edit Update in the ext above.. simplified it right down. So I think my problem is to do with the async pipe.. does it need setting up?
Solved it by stripping back and realising the problem wasn't so much the code but the approach and a mis-understand of angulars change management - see here:stackoverflow.com/questions/41265716/…, But thank you anyway.
0

I think your async getBizImg() is right. you could do it this way

ngOnInit() {
  this.getBizImg().then((wibble) => {
    console.log(wibble);
    // just add here this.urlImage = wibble
  });
}

on your component add a urlImage. and in the html

<ion-content padding>
   <ion-img *ngIf="urlImage" [src]="urlImage" ></ion-img>
</ion-content>

or if you want to call it from the html, I'am not sure but try the asyncPipe https://angular.io/api/common/AsyncPipe

<ion-content padding>
   <ion-img [src]="getBizImg() | async" ></ion-img>
</ion-content>

1 Comment

Thanks med, you were right ... My issue wasn't in my code so much as the approach and a mis-understanding of angular. It became clearer when I removed the calls to the back end (probably should have done that in the first place - but wasn't aware of this issue here: stackoverflow.com/questions/41265716/…).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.