@@ -237,55 +237,74 @@ 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- errors
244- . filter ( ( error : FormError ) => findIndex ( this . formErrors , {
245- fieldId : error . fieldId ,
246- fieldIndex : error . fieldIndex ,
247- } ) === - 1 )
248- . forEach ( ( error : FormError ) => {
249- const { fieldId } = error ;
250- const { fieldIndex } = error ;
251- let field : AbstractControl ;
252- if ( this . parentFormModel ) {
253- field = this . formBuilderService . getFormControlById ( fieldId , formGroup . parent as UntypedFormGroup , formModel , fieldIndex ) ;
254- } else {
255- field = this . formBuilderService . getFormControlById ( fieldId , formGroup , formModel , fieldIndex ) ;
256- }
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+ }
257254
258- if ( field ) {
259- const modelArrayIndex = fieldIndex > 0 ? fieldIndex : null ;
260- const model : DynamicFormControlModel = this . formBuilderService . findById ( fieldId , formModel , modelArrayIndex ) ;
261- this . formService . addErrorToField ( field , model , error . message ) ;
262- this . changeDetectorRef . detectChanges ( ) ;
263- }
264- } ) ;
265-
266- this . formErrors
267- . filter ( ( error : FormError ) => findIndex ( errors , {
268- fieldId : error . fieldId ,
269- fieldIndex : error . fieldIndex ,
270- } ) === - 1 )
271- . forEach ( ( error : FormError ) => {
272- const { fieldId } = error ;
273- const { fieldIndex } = error ;
274- let field : AbstractControl ;
275- if ( this . parentFormModel ) {
276- field = this . formBuilderService . getFormControlById ( fieldId , formGroup . parent as UntypedFormGroup , formModel , fieldIndex ) ;
277- } else {
278- 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 ) ;
279278 }
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+ if ( ! nextMap . has ( key ) && prevMap . has ( key ) ) {
295+ const control = getControl ( prev ) ;
296+ if ( control ) {
297+ const model = getModel ( prev ) ;
298+ this . formService . removeErrorFromField ( control , model , prev . message ) ;
299+ this . formService . removeError ( this . formId , prev . fieldId , prev . fieldIndex ) ;
300+ removedErrors . push ( prev ) ;
301+ }
302+ }
303+ } ) ;
280304
281- if ( field ) {
282- const model : DynamicFormControlModel = this . formBuilderService . findById ( fieldId , formModel , fieldIndex ) ;
283- this . formService . removeErrorFromField ( field , model , error . message ) ;
284- }
285- } ) ;
286- this . formErrors = errors ;
287- this . changeDetectorRef . detectChanges ( ) ;
288- } ) ,
305+ this . formErrors = this . formErrors . filter ( error => ! removedErrors . includes ( error ) ) ;
306+ this . changeDetectorRef . detectChanges ( ) ;
307+ } ) ,
289308 ) ;
290309 }
291310
0 commit comments