【问题标题】:Check if Observable is undefined检查 Observable 是否未定义
【发布时间】:2021-11-14 06:39:54
【问题描述】:

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

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

avatarUrl$ 是一个 observable,它是通过服务从数据库中获得的。

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

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

在这种情况下,我需要显示默认头像,例如:avatar-default.png。

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

我认为由于这种情况与未加载和正在加载但未定义的值没有区别?

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

我该如何解决这个问题?

【问题讨论】:

    标签: angular angular7


    【解决方案1】:

    似乎有点多余,你可以这样做:

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

    或者在你的组件中改变你的 observable:

    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 是对的,我应该读得更好。

    如果您希望它仅在加载后显示,您只需像这样更改 observable:

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

    你可以做这样的模板:

    模板

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

    【讨论】:

    • 不错的答案,它涵盖了 OP 需要 +1 的所有内容。 startWith 就是答案
    • 我喜欢这种方法,虽然我不认为它涵盖了 OP 的用例。因为这将始终首先显示默认值,然后再切换到返回的头像(如果存在)。虽然我认为 OP 只想在没有头像的情况下显示默认值
    【解决方案2】:

    你可以用 observable 的对象来实现。当你希望你的 observable 中的值 null、undefined 或 0 不被 *ngIf 阻塞时,它很有用

    <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>
    

    【讨论】:

      【解决方案3】:

      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>
      

      【讨论】:

        【解决方案4】:

        对我来说,当一个可观察值在触发值之前传递给 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

        【讨论】:

          猜你喜欢
          • 2017-05-25
          • 2019-10-19
          • 1970-01-01
          • 2018-09-09
          • 2011-08-15
          • 1970-01-01
          • 2016-04-14
          • 1970-01-01
          • 2011-07-10
          相关资源
          最近更新 更多