@@ -237,54 +237,75 @@ export class FormComponent implements OnDestroy, OnInit {
237237 this . formService . getForm ( this . formId ) . pipe (
238238 filter ( ( formState : FormEntry ) => ! ! formState && ( isNotEmpty ( formState . errors ) || isNotEmpty ( this . formErrors ) ) ) ,
239239 map ( ( formState ) => formState . errors ) ,
240- distinctUntilChanged ( ) )
241- . subscribe ( ( errors : FormError [ ] ) => {
242- const { formGroup, formModel } = this ;
243- const existingMessages = new Set ( this . formErrors . map ( e => e . message ) ) ;
244-
245- errors
246- . filter ( ( error : FormError ) => ! existingMessages . has ( error . message ) )
247- . forEach ( ( error : FormError ) => {
248- const { fieldId } = error ;
249- const { fieldIndex } = error ;
250- let field : AbstractControl ;
251- if ( this . parentFormModel ) {
252- field = this . formBuilderService . getFormControlById ( fieldId , formGroup . parent as UntypedFormGroup , formModel , fieldIndex ) ;
253- } else {
254- field = this . formBuilderService . getFormControlById ( fieldId , formGroup , formModel , fieldIndex ) ;
255- }
240+ distinctUntilChanged ( ) ,
241+ ) . subscribe ( ( errors : FormError [ ] ) => {
242+ const { formGroup, formModel } = this ;
243+
244+ const prevMap = new Map < string , FormError > (
245+ this . formErrors . map ( e => [ `${ e . fieldId } :${ e . fieldIndex } ` , e ] ) ,
246+ ) ;
247+ const nextMap = new Map < string , FormError > (
248+ errors . map ( e => [ `${ e . fieldId } :${ e . fieldIndex } ` , e ] ) ,
249+ ) ;
250+
251+ if ( isEqual ( prevMap , nextMap ) ) {
252+ return ;
253+ }
256254
257- if ( field ) {
258- const modelArrayIndex = fieldIndex > 0 ? fieldIndex : null ;
259- const model : DynamicFormControlModel = this . formBuilderService . findById ( fieldId , formModel , modelArrayIndex ) ;
260- this . formService . addErrorToField ( field , model , error . message ) ;
261- this . changeDetectorRef . detectChanges ( ) ;
262- }
263- } ) ;
264-
265- this . formErrors
266- . filter ( ( error : FormError ) => findIndex ( errors , {
267- fieldId : error . fieldId ,
268- fieldIndex : error . fieldIndex ,
269- } ) === - 1 )
270- . forEach ( ( error : FormError ) => {
271- const { fieldId } = error ;
272- const { fieldIndex } = error ;
273- let field : AbstractControl ;
274- if ( this . parentFormModel ) {
275- field = this . formBuilderService . getFormControlById ( fieldId , formGroup . parent as UntypedFormGroup , formModel , fieldIndex ) ;
276- } else {
277- field = this . formBuilderService . getFormControlById ( fieldId , formGroup , formModel , fieldIndex ) ;
255+ const getControl = ( err : FormError ) : AbstractControl | null => {
256+ return this . parentFormModel
257+ ? this . formBuilderService . getFormControlById ( err . fieldId , formGroup . parent as UntypedFormGroup , formModel , err . fieldIndex )
258+ : this . formBuilderService . getFormControlById ( err . fieldId , formGroup , formModel , err . fieldIndex ) ;
259+ } ;
260+
261+ const getModel = ( err : FormError ) : DynamicFormControlModel => {
262+ const modelArrayIndex = err . fieldIndex > 0 ? err . fieldIndex : null ;
263+ return this . formBuilderService . findById ( err . fieldId , formModel , modelArrayIndex ) ;
264+ } ;
265+ // Add or change (including revert) errors
266+ errors . forEach ( next => {
267+ const key = `${ next . fieldId } :${ next . fieldIndex } ` ;
268+ const prev = prevMap . get ( key ) ;
269+ if ( ! prev || prev . message !== next . message ) {
270+ // Remove old message if changed
271+ if ( prev ) {
272+ const prevControl = getControl ( prev ) ;
273+ if ( prevControl ) {
274+ const prevModel = getModel ( prev ) ;
275+ this . formService . removeErrorFromField ( prevControl , prevModel , prev . message ) ;
276+ this . formService . removeError ( this . formId , prev . fieldId , prev . fieldIndex ) ;
277+ this . formErrors . splice ( findIndex ( this . formErrors , prev ) , 1 ) ;
278278 }
279+ }
280+ // Add new message
281+ const control = getControl ( next ) ;
282+ if ( control ) {
283+ const model = getModel ( next ) ;
284+ this . formService . addErrorToField ( control , model , next . message ) ;
285+ this . formErrors . push ( next ) ;
286+ }
287+ }
288+ } ) ;
289+
290+ const removedErrors : FormError [ ] = [ ] ;
291+ // Remove errors for fields no longer present
292+ this . formErrors . forEach ( prev => {
293+ const key = `${ prev . fieldId } :${ prev . fieldIndex } ` ;
294+ console . log ( 'checking removal of' , key , prevMap . has ( key ) ) ;
295+ if ( ! nextMap . has ( key ) && prevMap . has ( key ) ) {
296+ const control = getControl ( prev ) ;
297+ if ( control ) {
298+ const model = getModel ( prev ) ;
299+ this . formService . removeErrorFromField ( control , model , prev . message ) ;
300+ this . formService . removeError ( this . formId , prev . fieldId , prev . fieldIndex ) ;
301+ removedErrors . push ( prev ) ;
302+ }
303+ }
304+ } ) ;
279305
280- if ( field ) {
281- const model : DynamicFormControlModel = this . formBuilderService . findById ( fieldId , formModel , fieldIndex ) ;
282- this . formService . removeErrorFromField ( field , model , error . message ) ;
283- }
284- } ) ;
285- this . formErrors = errors ;
286- this . changeDetectorRef . detectChanges ( ) ;
287- } ) ,
306+ this . formErrors = this . formErrors . filter ( error => ! removedErrors . includes ( error ) ) ;
307+ this . changeDetectorRef . detectChanges ( ) ;
308+ } ) ,
288309 ) ;
289310 }
290311
0 commit comments