On an Angular 7 application I have the following template:
<div *ngIf="avatarUrl$ | async;">
<ng-container *ngIf="avatarUrl$ | async as avatarUrl">
<img [src]="avatarUrl ? avatarUrl : 'avatar-default.png'">
</ng-container>
</div>
The avatarUrl$ is an observable as is obtained from a database through a service.
I want to display the IMG only after avatarUrl$ has a value loaded.
However, sometimes that value obtained from the service is undefined.
In that case I need to display the default avatar, e.g: avatar-default.png.
The problem is that avatar-default.png is not displayed when avatarUrl$ is undefined.
I think because of this condition that does not differentiate from the value not being loaded and being loaded but is undefined?
<div *ngIf="avatarUrl$ | async;">
How can I solve this?
Seems a bit redundant, you can do just this:
<div>
<img [src]="(avatarUrl$ | async) || 'avatar-default.png'">
</div>
Or change your observable in your component:
readonly avatarUrl$ = this.getAvatarFromSomeWhere().pipe(
startWith('avatar-default.png')
);
<div>
<img [src]="avatarUrl$ | async">
</div>
Then you don't need to do any || and just keep the template simple. This way only works when you are sure the request will return an avatar eventually
Otherwise you can expand a bit on it using map which will make sure it will always return a value:
private readonly defaultAvatar = 'avatar-default.png';
readonly avatarUrl$ = this.getAvatarFromSomeWhere().pipe(
map((avatar) => avatar || this.defaultAvatar),
startWith(this.defaultAvatar)
);
edit
@C_Ogoo is right, I should have read better.
In the case you want it to only show after it has been loaded, you just need to change the observable like this:
readonly avatarUrl$ = this.getAvatarFromSomeWhere().pipe(
map((avatar) => avatar || 'avatar-default.png')
);
and you can do the template like:
template
<div *ngIf="avatarUrl$ | async as avatarUrl">
<img [src]="avatarUrl">
</div>
You can achieve that with object of observable. It is usefull when you want the value null, undefined or 0 from your observable not to be blocked in the *ngIf
<div *ngIf="{url: avatarUrl$ | async} as data">
<img [src]="data.url ? data.url : 'avatar-default.png'">
</div>
It's good to know, that you can have multiple observables in your object if you want:
<div *ngIf="{url: avatarUrl$ | async, picture: pictureUrl$ | async} as data">
...
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With