通过订阅它来读取可观察值的值
Read value of observable with subscribing to it
我有一个像
这样的可观察对象
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$ observable,例如
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;
我想在不订阅 imageChangeSubscription 中可观察到的 imageOptions$ 的情况下执行此操作,以避免在侧面订阅中进行订阅,并且不在 TS 文件中使用额外的 属性
有什么办法吗?
您可以使用 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();
我喜欢@Joshua McCarthy 提供的答案,但您根本不需要订阅,您可以获得“更清洁”(取决于消费者的角度)版本。
关于 shareReplay(1)
避免额外副作用(它们通常是 API 调用,导致不希望的网络消耗)的声明的荣誉。我强烈建议您将它应用于可观察到的图像选项。
然后我将继续创建另一个可观察对象:
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(...){}
}
我有一个像
这样的可观察对象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$ observable,例如
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;
我想在不订阅 imageChangeSubscription 中可观察到的 imageOptions$ 的情况下执行此操作,以避免在侧面订阅中进行订阅,并且不在 TS 文件中使用额外的 属性
有什么办法吗?
您可以使用 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();
我喜欢@Joshua McCarthy 提供的答案,但您根本不需要订阅,您可以获得“更清洁”(取决于消费者的角度)版本。
关于 shareReplay(1)
避免额外副作用(它们通常是 API 调用,导致不希望的网络消耗)的声明的荣誉。我强烈建议您将它应用于可观察到的图像选项。
然后我将继续创建另一个可观察对象:
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(...){}
}