Ngx-formly: Hidden fields make form groups invalid

Created on 1 Apr 2020  路  3Comments  路  Source: ngx-formly/ngx-formly

Description
I'm checking the validity of a previous field (let's call it field "A") inside a hide expression. Here I receive the an incorrect validity state under the following conditions:

  • checkExpressionOn: 'modelChange'
  • field "A" has just been hidden (due to a hide expression)

This happens, because hidden fields are removed from the form after the hideExpressions are evaluated. This causes a bunch of strange behaviors in large, highly dynamic forms.

This is quite critical for us, since it blocks switching to "modelChange" and we really need the performance improvements of using "modelChange".

Minimal Reproduction

  • build a form with 2 groups
  • group 1 has at least one required field whose hideExpression evaluates to true
  • group 2's hideExpression checks if group 1 is valid

_Expected_:
Group 2 is displayed, since group 1 is valid (the required field is hidden)

_Actual_:
Group 2 is hidden, because Formly thinks group 1 is invalid

https://stackblitz.com/edit/ngx-formly-ui-material-sfqraf?file=src%2Fapp%2Fapp.module.ts

Your Environment

  • Angular version: 8.2.14
  • Formly version: 5.5.14 (latest)

Additional context
This "works" with expression check on change Detection Check, because the expression is simply evaluated one more time after the hidden form controls have been removed from the form.

This should really not behave differently whether you check expression on model change or on change detection check. I guess, the expressions should really be evaluated after a control has been added or removed. Of course, you then have to be careful to not produce a loop.

bug has workaround

All 3 comments

The expressions are evaluated after all controls have been built so probably there is something wrong with the hide observer.
I may try to check it later this week.

The fix would require more time but here is an alternative solution:

{
  key: 'container2',
  type: 'input',
  templateOptions: {
    label: 'Container2'
  },
-  hideExpression: () => {
-    console.log((this.firstField.formControl as FormGroup).controls)
-    return this.firstField.formControl.invalid;
-  },
+  hooks: {
+    onInit: (f) => {
+      const ffControl = this.firstField.formControl;
+      ffControl.statusChanges
+        .pipe(startWith(ffControl.invalid))
+        .subscribe((status) => f.hide = status === 'INVALID');
+    }
+  }
}

Okay, great. I'll try that out. Thanks for coming back to it. I'll keep you updated, if I'll experience any further issues.
This workaround seems reasonable for now.

Was this page helpful?
0 / 5 - 0 ratings