8

I'm working on creating a nested form group as shown in https://plnkr.co/edit/c93yFe2r83cvjiRvl6Uj?p=preview.

This is a fork of example from https://angular.io/docs/ts/latest/cookbook/form-validation.html#!#reactive

The example in Angular shows using validationMessages when the form does not have any nest groups. I'm not sure how to extend this when I have nested form groups. Following are sample form and validation messages I would create.

  buildForm(): void {
    this.heroForm = this.fb.group({
      'name': [this.hero.name, [
          Validators.required,
          Validators.minLength(4),
          Validators.maxLength(24),
          forbiddenNameValidator(/bob/i)
        ]
      ],
      'address': this.fb.group({
        'city': [''],
        'state': ['']
      }),
      'alterEgo': [this.hero.alterEgo],
      'power':    [this.hero.power, Validators.required]
    });

    this.heroForm.valueChanges
      .subscribe(data => this.onValueChanged(data));

    this.onValueChanged(); // (re)set validation messages now
  }

Expected formErrors and validationMessages

  formErrors = {
    'name': '',
    'power': '',
    'address': {
      'state': '',
      'city': ''
    }
  };

  validationMessages = {
    'name': {
      'required':      'Name is required.',
      'minlength':     'Name must be at least 4 characters long.',
      'maxlength':     'Name cannot be more than 24 characters long.',
      'forbiddenName': 'Someone named "Bob" cannot be a hero.'
    },
    'power': {
      'required': 'Power is required.'
    },
    'address': {
      'city': {
        'required':      'City is required.',
        'minlength':     'City must be at least 4 characters long.',
      },
      'state': {
        'required':      'State is required.',
        'minlength':     'State must be at least 4 characters long.',
      }
    }
  };

Following is the onValueChanged

  onValueChanged(data?: any) {
    if (!this.heroForm) { return; }
    const form = this.heroForm;

    for (const field in this.formErrors) {
      // clear previous error message (if any)
      this.formErrors[field] = '';
      const control = form.get(field);

      if (control && control.dirty && !control.valid) {
        const messages = this.validationMessages[field];
        for (const key in control.errors) {
          this.formErrors[field] += messages[key] + ' ';
        }
      }
    }
  }

How do I update the above onValueChanged function to support nested form groups validation ?

I'm doing above because I have a wizard form and I want to validate nested form group before moving to the next step in the wizard. Each wizard step contains a nested form group. The current wizard step must be valid before going to next. I don't want to put the content of wizard into multiple components because all the data must from the wizard must be submitted together at the end to a remote service. So I don't see value in complicated by having multiple components.

1

1 Answer 1

1

I know that this is an old story, but I was trying to get the validateAllFormGroups(formGroup: FormGroup) synchronously and I didn't find any answer somewhere so I implemented my approach:

function validateAllFormGroups(formGroup: FormGroup): boolean {
    let hasErrors = false;

    Object.keys(formGroup.controls).forEach((field) => {
      const control = formGroup.get(field);

      hasErrors =
        control instanceof FormGroup
          ? hasErrors || !validateAllFormGroups(control)
          : hasErrors || !!control?.errors;
    });

    return !hasErrors;
}

You can adapt it to get the results that the logic of your application needs, for me a boolean value was enough.

Any optimization or suggestion would be welcome

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.