Search code examples
javascriptangularobservablepipes-filters

Angular 2 async pipe on a function


I'm trying to get a base64 from an api. The following code works fine.

private test = null;

ngOnInit() {
   this.loadCustomers();
   this.test = this.getSiteImage();
}

getSiteImage() {
   return this.CustomerService.getCustomerSiteImage('test.com').share();
}

<img class="avatar avatar-xl" src="{{ (test | async)?.image }}" alt="">

But I would rather like to use a function. When I change the code to the following:

getSiteImage(url) {
    return this.CustomerService.getCustomerSiteImage(url).share();
}


<img class="avatar avatar-xl" src="{{ (getSiteImage('test.com') | async)?.image }}" alt="">

I like to know why this isn't working and how I can properly achieve this.

---------EDIT:

To help people with the same problem in the future. Just as @thinkinkingmedia suggested. I put the observables in an object with the url as key.

I changed the getSiteImage(url) methode to:

getSiteImage(url) {
    if (url in this.imageObservables) {
      return this.imageObservables[url];
    } else {
      this.imageObservables[url] = this.CustomerService.getCustomerSiteImage(url).share();
      return this.imageObservables[url];
    }
}

Solution

  • The reason it's not working is because async is getting a new observable every time Angular checks the expression for a change.

    In your first example:

    {{ (test | async)?.image }}
    

    Angular checks the expression which passes the value of the property test to async. Asycn then subscribes to the observable and waits for a value. In the next cycle of checking Angular passes the same observable to Async, and Async makes no changes as it's already subscribed.

    In your second example:

    {{ (getSiteImage('test.com') | async)?.image }}
    

    Angular checks the expression which calls a function that creates an observable. This is passed to async which waits for a response. In the next cycle this gets repeated. Each change detection creates a new observable and the async never gets a chance to yield a result. For every new observable passed to async it unsubscribes to the previous.