mgr/dashboard: Add custom validators.

Signed-off-by: Volker Theile <vtheile@suse.com>
This commit is contained in:
Volker Theile 2018-03-26 11:24:29 +02:00
parent aaac83abb5
commit 20a2ec5e94
2 changed files with 154 additions and 0 deletions

View File

@ -0,0 +1,89 @@
import { FormControl, FormGroup } from '@angular/forms';
import { CdValidators } from './cd-validators';
describe('CdValidators', () => {
describe('email', () => {
it('should not error on an empty email address', () => {
const control = new FormControl('');
expect(CdValidators.email(control)).toBeNull();
});
it('should not error on valid email address', () => {
const control = new FormControl('dashboard@ceph.com');
expect(CdValidators.email(control)).toBeNull();
});
it('should error on invalid email address', () => {
const control = new FormControl('xyz');
expect(CdValidators.email(control)).toEqual({'email': true});
});
});
describe('requiredIf', () => {
let form: FormGroup;
beforeEach(() => {
form = new FormGroup({
x: new FormControl(true),
y: new FormControl('abc'),
z: new FormControl('')
});
});
it('should not error because all conditions are fulfilled', () => {
form.get('z').setValue('zyx');
const validatorFn = CdValidators.requiredIf({
'x': true,
'y': 'abc'
});
expect(validatorFn(form.controls['z'])).toBeNull();
});
it('should not error because of unmet prerequisites', () => {
// Define prereqs that do not match the current values of the form fields.
const validatorFn = CdValidators.requiredIf({
'x': false,
'y': 'xyz'
});
// The validator must succeed because the prereqs do not match, so the
// validation of the 'z' control will be skipped.
expect(validatorFn(form.controls['z'])).toBeNull();
});
it('should error because of an empty value', () => {
// Define prereqs that force the validator to validate the value of
// the 'z' control.
const validatorFn = CdValidators.requiredIf({
'x': true,
'y': 'abc'
});
// The validator must fail because the value of control 'z' is empty.
expect(validatorFn(form.controls['z'])).toEqual({'required': true});
});
it('should not error because of unsuccessful condition', () => {
form.get('z').setValue('zyx');
// Define prereqs that force the validator to validate the value of
// the 'z' control.
const validatorFn = CdValidators.requiredIf({
'x': true,
'z': 'zyx'
}, () => false);
expect(validatorFn(form.controls['z'])).toBeNull();
});
it('should error because of successful condition', () => {
const conditionFn = (value) => {
return value === 'abc';
};
// Define prereqs that force the validator to validate the value of
// the 'y' control.
const validatorFn = CdValidators.requiredIf({
'x': true,
'z': ''
}, conditionFn);
expect(validatorFn(form.controls['y'])).toEqual({'required': true});
});
});
});

View File

@ -0,0 +1,65 @@
import {
AbstractControl,
ValidationErrors,
ValidatorFn,
Validators
} from '@angular/forms';
import * as _ from 'lodash';
type Prerequisites = { // tslint:disable-line
[key: string]: any
};
export function isEmptyInputValue(value: any): boolean {
return value == null || value.length === 0;
}
export class CdValidators {
/**
* Validator that performs email validation. In contrast to the Angular
* email validator an empty email will not be handled as invalid.
*/
static email(control: AbstractControl): ValidationErrors | null {
// Exit immediately if value is empty.
if (isEmptyInputValue(control.value)) {
return null;
}
return Validators.email(control);
}
/**
* Validator that requires controls to fulfill the specified condition if
* the specified prerequisites matches. If the prerequisites are fulfilled,
* then the given function is executed and if it succeeds, the 'required'
* validation error will be returned, otherwise null.
* @param {Prerequisites} prerequisites An object containing the prerequisites.
* ### Example
* ```typescript
* {
* 'generate_key': true,
* 'username': 'Max Mustermann'
* }
* ```
* Only if all prerequisites are fulfilled, then the validation of the
* control will be triggered.
* @param {Function | undefined} condition The function to be executed when all
* prerequisites are fulfilled. If not set, then the {@link isEmptyInputValue}
* function will be used by default. The control's value is used as function
* argument. The function must return true to set the validation error.
* @return {ValidatorFn} Returns the validator function.
*/
static requiredIf(prerequisites: Prerequisites, condition?: Function | undefined): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
// Check if all prerequisites matches.
if (!Object.keys(prerequisites).every((key) => {
return (control.parent && control.parent.get(key).value === prerequisites[key]);
})) {
return null;
}
const success = _.isFunction(condition) ? condition.call(condition, control.value) :
isEmptyInputValue(control.value);
return success ? {'required': true} : null;
};
}
}