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