FormManager pitfalls

Updating state property depending on other property using reactive forms

If you plan to update state property based on other form property for example: reset post code on house number change. When you type in hause number ipost code will reset but hause number input will remain unchanged. Please see code bellow

merge(
    this.form.controls.address.controls.addressSelectItem!.valueChanges,
    this.form.controls.address.controls.houseNr!.valueChanges,
)
    .pipe(
      safeTakeUntilDestroyed(this.destroyRef))
    .subscribe(() => {
        const addressSelectItemControl = this.form.controls.address.controls.addressSelectItem;
        const houseNrControl = this.form.controls.address.controls.houseNr;
        if (addressSelectItemControl?.dirty || houseNrControl?.dirty) {
            this.actions.resetPostalCode();
        }
    });
            
// actions code
resetPostalCode() {
    this.store.update((state) => {
        state.data.address.postalCode = '';
    });
}

Why did this happened? Because FormsManager has default debounceTime of 100ms before syncing form value to a state. Since post code state is updated before, so state update is synced first back to form with originl hause number value.

In order to fix that add debouncTime to code which will be greater that default FormsManager debounceTime

merge(
    this.form.controls.address.controls.addressSelectItem!.valueChanges,
    this.form.controls.address.controls.houseNr!.valueChanges,
)
    .pipe(
      debounceTime(150), // <----
      distinctUntilChanged(),
      safeTakeUntilDestroyed(this.destroyRef))
    .subscribe(() => {
        const addressSelectItemControl = this.form.controls.address.controls.addressSelectItem;
        const houseNrControl = this.form.controls.address.controls.houseNr;
        if (addressSelectItemControl?.dirty || houseNrControl?.dirty) {
            this.actions.resetPostalCode();
        }
    });

If 150ms seems to slow for you, you hav ealways a possibility to provide different debounceTime to FormsManager

this.ngFormStateManager = this.actions.store.select(['data'])
.form.bind(this.form, { 
    emitEvent: true,
    debounceTime: 50,
});

Last updated