检查Observable是否未定义



在Angular 7应用程序上,我有以下模板:

<div *ngIf="avatarUrl$ | async;">
<ng-container *ngIf="avatarUrl$ | async as avatarUrl">
<img [src]="avatarUrl ? avatarUrl : 'avatar-default.png'">
</ng-container>
</div>

CCD_ 1是通过服务从数据库获得的可观察的。

我只想在avatarUrl$加载了值之后显示IMG。

但是,有时从服务获得的值是未定义的。

在这种情况下,我需要显示默认的化身,例如:avatar-default.png

问题是当avatarUrl$未定义时,avatar-default.png不显示。

我认为是因为这个条件与未加载和正在加载但未定义的值没有区别?

<div *ngIf="avatarUrl$ | async;">

我该如何解决这个问题?

看起来有点多余,你可以这样做:

<div>
<img [src]="(avatarUrl$ | async) || 'avatar-default.png'">
</div>

或者更改组件中的可观测值:

readonly avatarUrl$ = this.getAvatarFromSomeWhere().pipe(
startWith('avatar-default.png')
);
<div>
<img [src]="avatarUrl$ | async">
</div>

那么您就不需要执行任何||,只需保持模板的简单即可。只有当你确定请求最终会返回一个头像时,这种方式才有效

否则,您可以使用map对其进行扩展,这将确保它始终返回一个值:

private readonly defaultAvatar = 'avatar-default.png';
readonly avatarUrl$ = this.getAvatarFromSomeWhere().pipe(
map((avatar) => avatar || this.defaultAvatar),
startWith(this.defaultAvatar)
);

编辑

@C_Ogoo是对的,我应该读得更好。

如果你想让它只在加载后显示,你只需要像这样更改可观察到的:

readonly avatarUrl$ = this.getAvatarFromSomeWhere().pipe(
map((avatar) => avatar || 'avatar-default.png')
);

你可以做这样的模板:

模板

<div *ngIf="avatarUrl$ | async as avatarUrl">
<img [src]="avatarUrl">
</div>

您可以通过observable对象来实现这一点。当您希望不在avatarUrl$1 中阻止可观察到的值nullundefined0时,它是有用的

<div *ngIf="{url: avatarUrl$ | async} as data">
<img [src]="data.url ? data.url : 'avatar-default.png'">
</div>

很高兴知道,如果你想的话,你可以在你的对象中有多个可观测对象:

<div *ngIf="{url: avatarUrl$ | async, picture: pictureUrl$ | async} as data">
...
</div>

Observable的第一个检查值是否未定义。。

<ng-container *ngIf= avatarUrl$ === 'undefined' | async ; else loaded >
<img [src]='avatar-default.png'>
</ng-container>
<ng-template #loaded >
<div *ngIf="avatarUrl$ | async;">
<img [src]="avatarUrl">
</div>
</ng-template>

对我来说,当一个可观察值在触发值之前传递给ngFor时,就会发生这种情况。

//component.ts
this.data = Array<string> | Observable<Array<string>>; 
this.data=getData(); // <---- this.data here already has a value
// getData() returns Observable<Array<string>>
this.data.subscribe(result=>{
this.data = result // <--- this.data value just changed witch introduces another issue
})
//template.html
<ng-container *ngIf="data;">
<!-- 
actually, data here has an observable value, so this template block will always executed
it's initial value is observable, which is neither an iterable nor undefined
--> 

{{ data }} <-- error occurs here
</ng-container>

此设计模式引入的另一个问题是,更改this.data值将使此模板块再次被评估,并且页面将被加载两次。

这里是正确的设计模式。

this.data: Array<string> | Observable<Array<string>>;
this.content: Array<string>; // <-- the initial value here is undefined which is correct
this.data = getData()
this.data.subscribe(result=>{
this.content = result; // <-- use this.content instead of this.data
})

在模板文件中使用content而不是data