@@ -10,7 +10,7 @@ export type DirtyMap<T> = {
1010 [ Key in keyof T ] ?: boolean ;
1111} ;
1212
13- export type ErrorType < T , Error > = Error | ( T extends { } ? ErrorMap < T , Error > : never ) ;
13+ export type ErrorType < T , Error > = Error | ( T extends { } ? ErrorMap < NonNullable < T > , Error > : never ) ;
1414
1515export type ErrorMap < T , Error > = {
1616 [ Key in keyof T ] ?: ErrorType < T [ Key ] , Error > ;
@@ -19,7 +19,7 @@ export type ErrorMap<T, Error> = {
1919export type DefaultError = string ;
2020export type DefaultState = { isSubmitting : boolean } ;
2121
22- export function memberCopy < T > ( value : T ) : T {
22+ function memberCopy < T > ( value : T ) : T {
2323 if ( Array . isArray ( value ) ) {
2424 return [ ...value ] as any ;
2525 } else if ( typeof value === "object" ) {
@@ -29,6 +29,12 @@ export function memberCopy<T>(value: T): T {
2929 }
3030}
3131
32+ function addDistinct < T extends any [ ] > ( arr1 : T , arr2 : T ) {
33+ for ( let i = 0 ; i < arr2 . length ; i ++ ) {
34+ if ( ! arr1 . includes ( arr2 [ i ] ) ) arr1 . push ( arr2 [ i ] ) ;
35+ }
36+ }
37+
3238/**
3339 * Compares 2 objects that only contain primitive fields (no object fields)
3440 * @returns true when different, false when 'equal', undefined when an object field was found.
@@ -155,8 +161,6 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
155161 notifyParent : boolean = true ,
156162 fireAny : boolean = true
157163 ) {
158- if ( key === "author" ) console . trace ( "setValueInternal" , key , value , dirty ) ;
159-
160164 let valueMap = isDefault ? this . defaultValues : this . values ;
161165 if ( value === undefined ) {
162166 if ( Array . isArray ( valueMap ) ) valueMap . splice ( key as number , 1 ) ;
@@ -312,11 +316,10 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
312316 * @param error The error.
313317 * @param notifyChild Should this form notify the child form about this change?
314318 * @param notifyParent Should this form notify the parent form about this change?
315- * @param setValuesWasUsed
316319 */
317320 public setError < Key extends keyof T > (
318321 key : Key ,
319- error : ErrorType < T [ Key ] , Error > | undefined ,
322+ error : ErrorType < NonNullable < T [ Key ] > , Error > | undefined ,
320323 notifyChild : boolean = true ,
321324 notifyParent : boolean = true ,
322325 fireAny : boolean = true
@@ -327,17 +330,16 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
327330 else this . errorMap [ key ] = error ;
328331
329332 if ( notifyChild && this . childMap [ key ] ) {
330- if ( typeof error === "object" ) {
331- let changed = this . childMap [ key ] ! . setErrors ( ( error as any ) ?? { } , true , false ) ;
332- if ( ! changed ) return false ;
333- } else {
334- this . childMap [ key ] ! . setErrors ( { } as any , true , false ) ;
335- }
333+ let changed = this . childMap [ key ] ! . setErrors ( error ?? ( { } as any ) , true , false ) ;
334+ if ( ! changed && error !== undefined ) return false ;
336335 }
337336
338337 this . fireListeners ( key ) ;
339338 if ( fireAny ) this . fireAnyListeners ( ) ; // When setValuesWasUsed, it will call fireAnyListener itself when all values were set
340- if ( notifyParent ) this . updateParentErrors ( ) ; // Will call setError on parent
339+
340+ if ( notifyParent && this instanceof ChildFormState ) {
341+ this . parent . setError ( this . name , this . error ? memberCopy ( this . errorMap ) : undefined , false , true ) ;
342+ }
341343 return true ;
342344 }
343345
@@ -348,34 +350,37 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
348350 * @param notifyParent Should this form notify the parent form about this change?
349351 */
350352 public setErrors ( errors : ErrorType < T , Error > , notifyChild : boolean = true , notifyParent : boolean = true ) {
353+ let keys = Object . keys ( this . errorMap ) ;
354+
351355 if ( typeof errors === "string" ) {
352356 if ( notifyParent && this instanceof ChildFormState ) {
353357 this . parent . setError ( this . name , errors , false , true ) ;
354358 }
355- return ;
356- }
357- let keys = Object . keys ( this . errorMap ) ;
358- let newKeys = Object . keys ( errors ) ;
359- for ( let i = 0 ; i < newKeys . length ; i ++ ) {
360- if ( ! keys . includes ( newKeys [ i ] ) ) keys . push ( newKeys [ i ] ) ;
359+ errors = { } as any ;
360+ } else {
361+ addDistinct ( keys , Object . keys ( errors ) ) ;
361362 }
363+
362364 let changed = false ;
363365 for ( let i = keys . length ; i >= 0 ; i -- ) {
364366 let key = keys [ i ] as keyof T ;
365367 if (
366368 this . setError (
367369 key ,
368- errors [ key ] as any ,
370+ ( errors as ErrorMap < T , Error > ) [ key ] as ErrorType < NonNullable < T [ keyof T ] > , Error > ,
369371 notifyChild ,
370- false , // Will call updateParentErrors by itself after all values have been copied, see 3 lines down
372+ false , // Will call this.parent.setError by itself after all values have been copied, see 3 lines down
371373 false // Will call fireAnyListener by itself after all values have been copied, see 3 lines down
372374 )
373375 )
374376 changed = true ;
375377 }
376378 if ( ! changed ) return false ;
379+
377380 this . fireAnyListeners ( ) ;
378- if ( notifyParent ) this . updateParentErrors ( ) ;
381+ if ( notifyParent && this instanceof ChildFormState ) {
382+ this . parent . setError ( this . name , this . error ? ( memberCopy ( this . errorMap ) as any ) : undefined , false , true ) ;
383+ }
379384 return true ;
380385 }
381386
@@ -512,10 +517,6 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
512517 // Not implemented for root form, as it does not have a parent
513518 }
514519
515- protected updateParentErrors ( ) {
516- // Not implemented for root form, as it does not have a parent
517- }
518-
519520 protected updateParentState ( ) {
520521 // Not implemented for root form, as it does not have a parent
521522 }
@@ -556,10 +557,6 @@ export class ChildFormState<Parent, Key extends keyof Parent, ParentState, Paren
556557 ) ;
557558 }
558559
559- protected updateParentErrors ( ) {
560- this . parent . setError ( this . name , this . error ? ( memberCopy ( this . errorMap ) as any ) : undefined , false , true ) ;
561- }
562-
563560 protected updateParentState ( ) {
564561 this . parent . setState ( memberCopy ( this . state ) , false , true ) ;
565562 }
0 commit comments