【问题标题】:Read value of observable with subscribing to it通过订阅它来读取 observable 的值
【发布时间】:2022-01-18 14:59:36
【问题描述】:

我有一个可观察的像

imageOptions$: Observable<BoundImagesToProject[]> = this.imagesService
.getBoundImages({ projectId: this.projectId })
.pipe(map((images) => (images.data)));

在模板中我像这样使用它

<div class="form-field input-group">
    <label for="image">Image</label>
    <mat-select id="image" class="select--full-width" placeholder="Image" formControlName="image">
      <mat-option *ngFor="let image of imageOptions$ | async" [value]="image.imageId">
        {{ image.name }}
      </mat-option>
    </mat-select>
    <mat-error *ngIf="createVmForm.get('image').getError('required') && createVmForm.get('image').dirty"
      >Field is required</mat-error
    >
  </div>

现在我想在 TS 文件中使用可观察的 imagesOptions$,例如

this.imageChangeSubscription = this.createVmForm.get('image').valueChanges.subscribe((value) => {
  this.selectedImageVolumeSize = this.imagesOptions$ // get array value and match id and get the size.

如果它是一个数组,它会是这样的

this.selectedImageVolumeSize = this.images.find((image) => image.imageId === value).size;

我想在不订阅 imageOptions$ 的情况下执行此操作

有什么办法吗?

【问题讨论】:

  • 查看 Rxjs 决策树以评估适合您的用例的最佳运算符:rxjs.dev/operator-decision-tree。最后,您希望将两个 observable 组合起来,以便只有一个订阅。
  • 不,没有办法。我建议做一些像tap(images =&gt; this.size = images.find(...).size) 这样的黑客攻击是最好的。但是这样的代码将依赖于模板内的订阅

标签: javascript angular typescript rxjs observable


【解决方案1】:

您可以使用switchMap() 来避免嵌套订阅。但是您应该更新imagesOptions$,以便它可以使用shareReplay() 运算符与多个订阅者共享其最新值。

imageOptions$: Observable<BoundImagesToProject[]> = this.imagesService
  .getBoundImages({ projectId: this.projectId })
  .pipe(
    map(({data}) => data),
    shareReplay(1)
  );

然后在您的订阅中,从imageOptions$ 获取最新值以找到您的尺码。

this.imageChangeSubscription = this.createVmForm
  .get('image').valueChanges
  .pipe(
    switchMap(value => this.imagesOptions$
      .pipe(
        map(images => images.find(({imageId}) => imageId===value ))
      )
    )
  ).subscribe();

【讨论】:

    【解决方案2】:

    我喜欢@Joshua McCarthy 提供的答案,但您根本不需要订阅,您可以获得“更清洁”(取决于消费者的角度)版本。

    感谢关于 shareReplay(1) 的声明以避免额外的副作用(它们通常是 API 调用,导致不希望的网络消耗)。我强烈建议您将其应用于可观察的图像选项。

    然后我会继续创建另一个 observable:

    import { combineLatest, shareReplay } from 'rxjs/operators'
    
    @Component({...})
    export class YourComponent {
        ...
        ...
        selectedImageVolumeSize$ = combineLatest([this.createVmForm['image'].valueChanges, this.imagesOptions$]).pipe(
            map(([selectedImageId, imageOptions] => imageOptions.find(item => item.id === selectedImageId)
    
        )
    
        constructor(...){}
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多