0
votes

I am learning programming...

I am making some kind of forum using angularfire2 (firebase) I have 2 services, one that manages all user profile data and the other the messages. With an *ngfor I display all the messages (calling a function of the service in the component). The message interface has the uid of the user that submitted the message. With this uid I want to get the user profile picture for example to be displayed in the message.

The problem is that when I call the function I get an Observable inside an observable and my app starts a bucle. What do I am doing wrong?

Thanks!

admin.requests.component.html .

    <div *ngFor="let request of requests" class="card shadow">



    ..img  ... src="{{getUserProfilePicture(request.clientId)}}" ... ">

getUserProfilePicture(uid) returns the value of the imgURL of the DOC where uid = clientId

1
Are you saying requests is an array of observables? Or is it that getUserProfilePicture returns an observable? - Dean
I mean getUserProfilePicture returns an observable. Thanks - Ignacio Lombardi

1 Answers

1
votes

You're looking for the async pipe:

The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks.

So, if your observable returns a string with your image src, your refactored code might look like:

    ..img  ... src="{{getUserProfilePicture(request.clientId) | async}}" ... ">

I created a working example of the async pipe in an ngFor loop for reference.

Some potential things to watch out for with the async pipe: every time you use that same observable, it will subscribe to the observable again unless you capture the value using the as syntax. What this means is: if you have an async pipe that calls a web service, for example, it will be called multiple times if you do something like this:

<!-- Async pipe subscribes once... -->
<img src="{{someHttpCall(request.clientId) | async}}"/>
<!-- Async pipe subscribes again... -->
<p>Img loaded from: {{someHttpCall(request.clientId) | async}}</p>

If you wanted to refactor the above to us the as syntax to capture the output and avoid multiple server calls, it would look like this:

<!-- Capture our observable to prevent subsequent subscriptions. 
     Async pipe only subscribes once. -->
<ng-container *ngIf="someHttpCall(request.clientId) | async as imgSrc">
   <img src="{{ imgSrc }}"/>
   <!-- Also note we don't need the async pipe because it already subscribed 
        to the observable for us and we captured the value in our template -->
   <p>Img loaded from: {{ imgSrc }}</p>
</ng-container>

Anyway, that's a pitfall that a lot of new Angular developers fall into so I figured I wouldn't introduce the async pipe without at least a little word of caution.