0
votes

Please Refer to my plunkr

I've been playing around with the new Angular 2 RC and I think I have figured out how the form validation works.

First I build 2 objects called defaultValidationMessages and formDefinition

private defaultValidationMessages: { [id: string]: string };

formDefinition: {
    [fieldname: string]:
    {
        displayName: string,
        placeholder: string,
        currentErrorMessage: string,
        customValidationMessages: { [errorKey: string]: string }
        defaultValidators: ValidatorFn,
        defaultValue: any
    }
};

Then I load up those objects with the default validators and field information. and build the ControlGroup from the formDefinition object.

    this.defaultValidationMessages = {
        'required': '{displayName} is required',
        'minlength': '{displayName} must be at least {minlength} characters',
        'maxlength': '{displayName} cannot exceed {maxlength} characters',
        'pattern': '{displayName} is not valid'
    }

    this.formDefinition = {
        'name': {
            displayName: 'Name',
            placeholder: '',
            currentErrorMessage: '',
            customValidationMessages: {},
            defaultValidators: Validators.compose(
                [
                    Validators.required,
                    Validators.minLength(3),
                    Validators.maxLength(50)
                ]),
            defaultValue: this.person.name
        },
        'isEmployee': {
            displayName: 'Is Employee',
            placeholder: '',
            currentErrorMessage: '',
            customValidationMessages: {},
            defaultValidators: Validators.compose([]),
            defaultValue: this.person.isEmployee
        },
        'employeeId': {
            displayName: 'Employee Id',
            placeholder: '',
            currentErrorMessage: '',
            customValidationMessages: { 'pattern': '{displayName} must be 5 numerical digits' },
            defaultValidators: Validators.compose(
                [
                    Validators.pattern((/\d{5}/).source)
                ]),
            defaultValue: this.person.employeeId
        }
    }
    this.personForm = this.formBuilder.group({});
    for (var v in this.formDefinition) {
        this.personForm.addControl(v, new Control(this.formDefinition[v].defaultValue, this.formDefinition[v].defaultValidators));
    }

    this.personForm.valueChanges
        .map(value => {
            return value;
        })
        .subscribe(data => this.onValueChanged(data));

Using a technique that I learned from Deborah Kurata's ng-conf 2016 session I bind a method to the ControlGroups valueChanges event.

By defining sets of default validators on each control it allows the control to dynamically append new validators to it based on future action. And then clearing back to the default validators later.

Issue I still have.

I was having an issue getting my typescript intellisense to import the ValidatorFn type. I found it here but I don't think I'm suppose to access it like this:

import { ValidatorFn } from '../../../node_modules/@angular/common/src/forms/directives/validators'

I also had to reset the form by setting some internal members. Is there a better way to reset the form? see below:

(<any> this.programForm.controls[v])._touched = false;
(<any> this.programForm.controls[v])._dirty = false;
(<any> this.programForm.controls[v])._pristine = true;

Please look at my plunk and let me know if there is a better way to handle model driven dynamic form validation?

1

1 Answers

0
votes

My import string looks like this and it isn't marked as an error.

import { ValidatorFn } from '@angular/common/src/forms/directives/validators';

And some info about the reset form issue. There is not proper reset feature available yet, but a workaround exists. I've found it in docs.

You need a component field

active: true;

and you need to check it in your form tag:

<form *ngIf="active">

After that you should change your personFormSubmit() method to:

personFormSubmit() {
  this.person = new Person();
  this.active = false;
  setTimeout(()=> {
    this.active=true;
    this.changeDetectorRef.detectChanges();
    alert("Form submitted and reset.");
  }, 0);
}

I tried this solution with you plnkr example and seems that it works.