'rxjs date range picker always wait for start and end observables

I have an angular material date picker and i'm trying get the start date and end date observables before I submit my query

component.html

        <mat-form-field>
        <mat-label>Date Range</mat-label>
        <button mat-button matSuffix mat-icon-button aria-label="Clear" type="button" (click)="clearDate()">
            <mat-icon>close</mat-icon>
        </button>
        <mat-date-range-input [formGroup]="dateRangeGroup" [rangePicker]="picker">
          <input matEndDate formControlName="end" placeholder="End date">
          <input matStartDate formControlName="start" placeholder="Start date">
        </mat-date-range-input>
        <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
        <mat-date-range-picker #picker></mat-date-range-picker>
    </mat-form-field>

component.ts

constructor(
public svcA: ServiceA,
public svcB: ServiceB,
) {

// ignore this, just for debugging
this.dateRangeGroup.controls['start'].valueChanges.pipe(filter(res => res !== null)).subscribe(val => console.log('start date', val));
this.dateRangeGroup.controls['end'].valueChanges.pipe(filter(res => res !== null)).subscribe(val => console.log('end date', val));


 combineLatest([
    this.dateRangeGroup.controls['start'].valueChanges.pipe(filter(res => res !== null)),
    this.dateRangeGroup.controls['end'].valueChanges.pipe(filter(res => res !== null))
    ])
    .subscribe(([start, end]) => {
        console.log(`combineLatest ${start} - ${end}`);
        this.svcA.sendQuery(start, end);
    },
    err => {
        console.log('error', err)
    },
    () => {
        console.log('complete');
    });

// set default date range search to 30 days
this.clearDate();

}

combineLatest works perfectly for what I want in the beginning as it waits for both to fire an event first, except it then emits each individual date selection after the first event has been fired (selecting start & end date). This causes an unpleasant UI experience when the query is submitted half way through a user selecting dates

How can I wait for both long lived observables so that I can ensure a start and end date has been selected each time a user decides to change the date ranges?



Solution 1:[1]

I'm not sure why you're handling the submit using the FormControl's valueChanges Observables, instead of using a submit button.

Anyway, if it's the only available option, you can use the RxJS zip operator instead of the combineLatest one.

The zip operator waits each time until both of the streams emit a value, then combine them in an array.

Combines multiple Observables to create an Observable whose values are calculated from the values, in order, of each of its input Observables.

zip([
  this.dateRangeGroup.controls['start'].valueChanges.pipe(
    filter((res) => res !== null)
  ),
  this.dateRangeGroup.controls['end'].valueChanges.pipe(
    filter((res) => res !== null)
  ),
]).subscribe(
  ([start, end]) => {
    console.log(`combineLatest ${start} - ${end}`);
    this.svcA.sendQuery(start, end);
  },
  (err) => {
    console.log('error', err);
  },
  () => {
    console.log('complete');
  }
);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1