Read value of observable with subscribing to it

I have an observable like

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

and in the template I use it like

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

Now I want to use the imagesOptions$ observable in the TS file like

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

If it was an array it would be like

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

I want to do it without subscribing to imageOptions$ observable in the imageChangeSubscription to avoid subscribtion in side subscription and without using an extra property in the TS file

Any way to do it?


Solution 1:

You can use switchMap() to avoid nested subscriptions. But you should update imagesOptions$ so it can share its latest value with multiple subscribers using the shareReplay() operator.

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

Then in your subscription, grab the latest value from imageOptions$ to find your size.

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