From afb3f964564b5b9795071b4f8fcfbaad9f37feec Mon Sep 17 00:00:00 2001 From: Derek Burgman Date: Thu, 12 May 2022 00:59:18 -0500 Subject: [PATCH] fix: fixed dbxFormlyForm async validation issue - Fixed issue where the async form status was not taking into account, causing values to be returned as valid before async validation finished. Now status values are passed through and cause updates on the overall state. - Added status to DbxFormEvent --- packages/dbx-form/src/lib/form/form.ts | 2 ++ packages/dbx-form/src/lib/formly/formly.context.ts | 4 ++-- .../dbx-form/src/lib/formly/formly.form.component.ts | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/dbx-form/src/lib/form/form.ts b/packages/dbx-form/src/lib/form/form.ts index e0679943e..95242b771 100644 --- a/packages/dbx-form/src/lib/form/form.ts +++ b/packages/dbx-form/src/lib/form/form.ts @@ -2,6 +2,7 @@ import { forwardRef, Provider, Type } from '@angular/core'; import { Observable } from 'rxjs'; import { LockSet } from '@dereekb/rxjs'; import { BooleanStringKeyArray, Maybe } from '@dereekb/util'; +import { FormControlStatus } from '@angular/forms'; /** * Current state of a DbxForm @@ -26,6 +27,7 @@ export const DEFAULT_FORM_DISABLED_KEY = 'dbx_form_disabled'; export interface DbxFormEvent { readonly isComplete: boolean; readonly state: DbxFormState; + readonly status: FormControlStatus; readonly pristine?: boolean; readonly untouched?: boolean; readonly lastResetAt?: Date; diff --git a/packages/dbx-form/src/lib/formly/formly.context.ts b/packages/dbx-form/src/lib/formly/formly.context.ts index 18054379d..fb2bd1984 100644 --- a/packages/dbx-form/src/lib/formly/formly.context.ts +++ b/packages/dbx-form/src/lib/formly/formly.context.ts @@ -2,7 +2,7 @@ import { Provider } from '@angular/core'; import { BehaviorSubject, Observable, of, switchMap, shareReplay, distinctUntilChanged } from 'rxjs'; import { DbxForm, DbxFormDisabledKey, DbxFormEvent, DbxFormState, DbxMutableForm, DEFAULT_FORM_DISABLED_KEY, ProvideDbxMutableForm } from '../form/form'; import { FormlyFieldConfig } from '@ngx-formly/core'; -import { LockSet, filterMaybe } from '@dereekb/rxjs'; +import { LockSet, filterMaybe, tapLog } from '@dereekb/rxjs'; import { BooleanStringKeyArray, BooleanStringKeyArrayUtilityInstance, Maybe } from '@dereekb/util'; export interface DbxFormlyInitialize { @@ -39,7 +39,7 @@ export class DbxFormlyContext implements DbxForm { readonly lockSet = new LockSet(); - private static INITIAL_STATE = { isComplete: false, state: DbxFormState.INITIALIZING }; + private static INITIAL_STATE: DbxFormEvent = { isComplete: false, state: DbxFormState.INITIALIZING, status: 'PENDING' }; private _fields = new BehaviorSubject>(undefined); private _initialValue = new BehaviorSubject>>(undefined); diff --git a/packages/dbx-form/src/lib/formly/formly.form.component.ts b/packages/dbx-form/src/lib/formly/formly.form.component.ts index 856b3e038..ed2259228 100644 --- a/packages/dbx-form/src/lib/formly/formly.form.component.ts +++ b/packages/dbx-form/src/lib/formly/formly.form.component.ts @@ -1,7 +1,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { FormlyFieldConfig, FormlyFormOptions } from '@ngx-formly/core'; -import { distinctUntilChanged, map, throttleTime, startWith, BehaviorSubject, Observable, Subject, switchMap, shareReplay, of, scan } from 'rxjs'; +import { distinctUntilChanged, map, throttleTime, startWith, BehaviorSubject, Observable, Subject, switchMap, shareReplay, of, scan, filter, first, combineLatest } from 'rxjs'; import { AbstractSubscriptionDirective } from '@dereekb/dbx-core'; import { DbxForm, DbxFormDisabledKey, DbxFormEvent, DbxFormState, DEFAULT_FORM_DISABLED_KEY, ProvideDbxMutableForm } from '../form/form'; import { DbxFormlyContext, DbxFormlyContextDelegate, DbxFormlyInitialize } from './formly.context'; @@ -35,7 +35,7 @@ export interface DbxFormlyFormState { export class DbxFormlyFormComponent extends AbstractSubscriptionDirective implements DbxForm, DbxFormlyContextDelegate, OnInit, OnDestroy { private _fields = new BehaviorSubject>>(undefined); - private _events = new BehaviorSubject({ isComplete: false, state: DbxFormState.INITIALIZING }); + private _events = new BehaviorSubject({ isComplete: false, state: DbxFormState.INITIALIZING, status: 'PENDING' }); private _disabled = new BehaviorSubject(undefined); private _reset = new BehaviorSubject(new Date()); @@ -55,9 +55,11 @@ export class DbxFormlyFormComponent extends AbstractSubscripti distinctUntilChanged(), throttleTime(50, undefined, { leading: true, trailing: true }), scanCount(), + // update on validation changes too. + switchMap(x => this.form.statusChanges.pipe(startWith(this.form.status), distinctUntilChanged()).pipe(map(_ => x))), map((changesSinceLastResetCount: number) => ({ changesSinceLastResetCount, - isFormValid: this.form.valid, + isFormValid: this.form.status !== 'PENDING' && this.form.valid, isFormDisabled: this.form.disabled })), scan((acc: DbxFormlyFormState, next: DbxFormlyFormState) => { @@ -82,6 +84,7 @@ export class DbxFormlyFormComponent extends AbstractSubscripti const nextState: DbxFormEvent = { isComplete: complete, state: (isReset) ? DbxFormState.RESET : DbxFormState.USED, + status: this.form.status, untouched: this.form.untouched, pristine: this.form.pristine, changesCount: changesSinceLastResetCount,