I\'m trying to add form validations which don\'t invalidate the form. The validation should only appear as warnings.
E.g. an age validation. An age greater than 90 shows
Ok
its can be easy by angular.io for form validation hinting you can read documents on https://angular.io/docs/ts/latest/cookbook/form-validation.html
but the similar way that can help you better may be in my mind.
first we create a abstract class named Form it contains some common function and properties.
import {FormGroup} from "@angular/forms";
export abstract class Form {
form: FormGroup;
protected abstract formErrors: Object;
protected abstract validationMessages: Object;
onValueChanged(data?: any) {
if (!this.form) { return; }
const form = this.form;
for (const field in this.formErrors) {
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];
break;
}
}
}
}
}
then you should to create a form component for example named LoginComponent like below
import {Component, OnInit} from "@angular/core";
import {Form} from "./form";
import {Validators, FormBuilder} from "@angular/forms";
@Component({
templateUrl: '...'
})
export class LoginComponent extends Form implements OnInit {
protected formErrors = {
'email': '',
'password': ''
}
protected validationMessages = {
'email': {
'required': 'email required message',
'email': 'email validation message'
},
'password': {
'required': 'password required message',
'minlength': 'password min length message',
'maxlength': 'password max length message',
}
}
constructor(private _fb: FormBuilder) { }
ngOnInit() {
this.buildForm();
}
buildForm() {
this.form = this._fb.group({
'email': ['', [
Validators.required,
// emailValidator
]],
'password': ['', [
Validators.required,
Validators.minLength(8),
Validators.maxLength(30)
]]
});
this.form.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged(); //
}
}
first we should inject FormBuilder for reactive forms (do not forgot to import ReactiveFormModule in your main module) and then in [buildForm()] method we build a group of form on form property that was inherited from abstract class Form.
then in next we create a subscribe for form value changes and on value change we call [onValueChanged()] method.
in [onValueChanged()] method we check the fields of form has valid or not, if not we get the message from protected validationMessages property and show it in formErrors property.
then your template should be similar this
the template is so easy, inner you check the field has error or not if has the error bind.
for bootstrap you can do something else like below
{{ formErrors.email }}
UPDATE: I attempt to create a very simple but almost complete sample for you certainly you can develop it for wilder scale : https://embed.plnkr.co/ExRUOtSrJV9VQfsRfkkJ/
but a little describe for that, you can create a custom validations like below
import {ValidatorFn, AbstractControl} from '@angular/forms';
function isEmptyInputValue(value: any) {
return value == null || typeof value === 'string' && value.length === 0;
}
export class MQValidators {
static age(max: number, validatorName: string = 'age'): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
if (isEmptyInputValue(control.value)) return null;
const value = typeof control.value == 'number' ? control.value : parseInt(control.value);
if (isNaN(value)) return null;
if (value <= max) return null;
let result = {};
result[validatorName] = {valid: false};
return result;
}
}
}
this custom validator get a optional param named validatorName, this param cause you designate multi similar validation as in your example the formComponent should be like below :
buildForm () {
this.form = this._fb.group({
'age': ['', [
Validators.required,
Validators.pattern('[0-9]*'),
MQValidators.age(90, 'abnormalAge'),
MQValidators.age(120, 'incredibleAge')
]]
});
this.form.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any): void {
if (!this.form) { return; }
const form = this.form;
for (const field in this.formErrors) {
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];
}
}
}
}
formErrors = {
age: ''
}
validationMessages = {
'age': {
'required': 'age is required.',
'pattern': 'age should be integer.',
'abnormalAge': 'age higher than 90 is abnormal !!!',
'incredibleAge': 'age higher than 120 is incredible !!!'
}
}
Hope I helped.