Skip to content

Commit

Permalink
feat(editors): add min/max length options to text editors (#30)
Browse files Browse the repository at this point in the history
* feat(editors): add min/max length options to text editors
- add a text length counter (currentTextLength/maxLength) to the LongText Editor
- the new `minLenght`, `maxLength` options can be used by the following Editors (autoComplete, longText, text)
- also flip the position of the Cancel/Save buttons, Cancel should be on the left and Save on the right
  • Loading branch information
ghiscoding authored Jul 28, 2020
1 parent a74799f commit 318c70c
Show file tree
Hide file tree
Showing 13 changed files with 497 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export class Example3 {
model: Editors.longText,
required: true,
alwaysSaveOnEnterKey: true,
minLength: 5,
maxLength: 255,
},
filterable: true,
grouping: {
Expand Down
5 changes: 5 additions & 0 deletions packages/common/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,9 @@ export class Constants {
static VALIDATION_EDITOR_NUMBER_MIN = 'Please enter a valid number that is greater than {{minValue}}';
static VALIDATION_EDITOR_NUMBER_MIN_INCLUSIVE = 'Please enter a valid number that is greater than or equal to {{minValue}}';
static VALIDATION_EDITOR_DECIMAL_BETWEEN = 'Please enter a valid number with a maximum of {{maxDecimal}} decimals';
static VALIDATION_EDITOR_TEXT_LENGTH_BETWEEN = 'Please make sure your text length is between {{minLength}} and {{maxLength}} characters';
static VALIDATION_EDITOR_TEXT_MAX_LENGTH = 'Please make sure your text is less than {{maxLength}} characters';
static VALIDATION_EDITOR_TEXT_MAX_LENGTH_INCLUSIVE = 'Please make sure your text is less than or equal to {{maxLength}} characters';
static VALIDATION_EDITOR_TEXT_MIN_LENGTH = 'Please make sure your text is more than {{minLength}} character(s)';
static VALIDATION_EDITOR_TEXT_MIN_LENGTH_INCLUSIVE = 'Please make sure your text is at least {{minLength}} character(s)';
}
8 changes: 3 additions & 5 deletions packages/common/src/editorValidators/integerValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,20 @@ export function integerValidator(inputValue: any, options: IntegerValidatorOptio
isValid = false;
outputMsg = errorMsg || Constants.VALIDATION_EDITOR_VALID_INTEGER;
} else if (minValue !== undefined && maxValue !== undefined && intNumber !== null && ((operatorConditionalType === 'exclusive' && (intNumber <= minValue || intNumber >= maxValue)) || (operatorConditionalType === 'inclusive' && (intNumber < minValue || intNumber > maxValue)))) {
// MIN & MAX Values provided
// MIN & MAX Values provided (between)
// when decimal value is bigger than 0, we only accept the decimal values as that value set
// for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
isValid = false;
outputMsg = errorMsg || Constants.VALIDATION_EDITOR_INTEGER_BETWEEN.replace(/{{minValue}}|{{maxValue}}/gi, (matched) => mapValidation[matched]);
} else if (minValue !== undefined && intNumber !== null && ((operatorConditionalType === 'exclusive' && intNumber <= minValue) || (operatorConditionalType === 'inclusive' && intNumber !== null && intNumber < minValue))) {
// MIN VALUE ONLY
// when decimal value is bigger than 0, we only accept the decimal values as that value set
// for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
// when decimal value has to be higher then provided minValue
isValid = false;
const defaultErrorMsg = operatorConditionalType === 'inclusive' ? Constants.VALIDATION_EDITOR_INTEGER_MIN_INCLUSIVE : Constants.VALIDATION_EDITOR_INTEGER_MIN;
outputMsg = errorMsg || defaultErrorMsg.replace(/{{minValue}}/gi, (matched) => mapValidation[matched]);
} else if (maxValue !== undefined && intNumber !== null && ((operatorConditionalType === 'exclusive' && intNumber >= maxValue) || (operatorConditionalType === 'inclusive' && intNumber !== null && intNumber > maxValue))) {
// MAX VALUE ONLY
// when decimal value is bigger than 0, we only accept the decimal values as that value set
// for example if we set decimalPlaces to 2, we will only accept numbers between 0 and 2 decimals
// when decimal value has to be lower then provided maxValue
isValid = false;
const defaultErrorMsg = operatorConditionalType === 'inclusive' ? Constants.VALIDATION_EDITOR_INTEGER_MAX_INCLUSIVE : Constants.VALIDATION_EDITOR_INTEGER_MAX;
outputMsg = errorMsg || defaultErrorMsg.replace(/{{maxValue}}/gi, (matched) => mapValidation[matched]);
Expand Down
40 changes: 34 additions & 6 deletions packages/common/src/editorValidators/textValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,53 @@ import { EditorValidator } from '../interfaces/editorValidator.interface';
interface TextValidatorOptions {
editorArgs: any;
errorMessage?: string;
minLength?: number;
maxLength?: number;
operatorConditionalType?: 'inclusive' | 'exclusive';
required?: boolean;
validator?: EditorValidator;
}

export function textValidator(inputValue: any, options: TextValidatorOptions): EditorValidatorOutput {
const isRequired = options.required;
const errorMsg = options.errorMessage;
const isRequired = options.required;
const minLength = options.minLength;
const maxLength = options.maxLength;
const operatorConditionalType = options.operatorConditionalType || 'inclusive';
const mapValidation = {
'{{minLength}}': minLength,
'{{maxLength}}': maxLength
};
let isValid = true;
let outputMsg = '';
const inputValueLength = inputValue.length;

if (options.validator) {
return options.validator(inputValue, options.editorArgs);
}

// by default the editor is almost always valid (except when it's required but not provided)
if (isRequired && inputValue === '') {
return {
valid: false,
msg: errorMsg || Constants.VALIDATION_REQUIRED_FIELD
};
isValid = false;
outputMsg = errorMsg || Constants.VALIDATION_REQUIRED_FIELD;
} else if (minLength !== undefined && maxLength !== undefined && ((operatorConditionalType === 'exclusive' && (inputValueLength <= minLength || inputValueLength >= maxLength)) || (operatorConditionalType === 'inclusive' && (inputValueLength < minLength || inputValueLength > maxLength)))) {
// MIN & MAX Length provided
// make sure text length is between minLength and maxLength
isValid = false;
outputMsg = errorMsg || Constants.VALIDATION_EDITOR_TEXT_LENGTH_BETWEEN.replace(/{{minLength}}|{{maxLength}}/gi, (matched) => mapValidation[matched]);
} else if (minLength !== undefined && inputValueLength !== null && ((operatorConditionalType === 'exclusive' && inputValueLength <= minLength) || (operatorConditionalType === 'inclusive' && inputValueLength !== null && inputValueLength < minLength))) {
// MIN Length ONLY
// when text length is shorter than minLength
isValid = false;
const defaultErrorMsg = operatorConditionalType === 'inclusive' ? Constants.VALIDATION_EDITOR_TEXT_MIN_LENGTH_INCLUSIVE : Constants.VALIDATION_EDITOR_TEXT_MIN_LENGTH;
outputMsg = errorMsg || defaultErrorMsg.replace(/{{minLength}}/gi, (matched) => mapValidation[matched]);
} else if (maxLength !== undefined && inputValueLength !== null && ((operatorConditionalType === 'exclusive' && inputValueLength >= maxLength) || (operatorConditionalType === 'inclusive' && inputValueLength !== null && inputValueLength > maxLength))) {
// MAX Length ONLY
// when text length is longer than minLength
isValid = false;
const defaultErrorMsg = operatorConditionalType === 'inclusive' ? Constants.VALIDATION_EDITOR_TEXT_MAX_LENGTH_INCLUSIVE : Constants.VALIDATION_EDITOR_TEXT_MAX_LENGTH;
outputMsg = errorMsg || defaultErrorMsg.replace(/{{maxLength}}/gi, (matched) => mapValidation[matched]);
}

return { valid: true, msg: null };
return { valid: isValid, msg: outputMsg };
}
124 changes: 120 additions & 4 deletions packages/common/src/editors/__tests__/autoCompleteEditor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,20 +385,136 @@ describe('AutoCompleteEditor', () => {
});

describe('validate method', () => {
it('should validate and return False when field is required and field is an empty string', () => {
it('should return False when field is required and field is empty', () => {
mockColumn.internalColumnEditor.required = true;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('');

expect(validation).toEqual({ valid: false, msg: 'Field is required' });
});

it('should validate and return True when field is required and field is a valid input value', () => {
it('should return True when field is required and input is a valid input value', () => {
mockColumn.internalColumnEditor.required = true;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('gender');
const validation = editor.validate('text');

expect(validation).toEqual({ valid: true, msg: null });
expect(validation).toEqual({ valid: true, msg: '' });
});

it('should return False when field is lower than a minLength defined', () => {
mockColumn.internalColumnEditor.minLength = 5;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text is at least 5 character(s)' });
});

it('should return False when field is lower than a minLength defined using exclusive operator', () => {
mockColumn.internalColumnEditor.minLength = 5;
mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive';
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text is more than 5 character(s)' });
});

it('should return True when field is equal to the minLength defined', () => {
mockColumn.internalColumnEditor.minLength = 4;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text');

expect(validation).toEqual({ valid: true, msg: '' });
});

it('should return False when field is greater than a maxLength defined', () => {
mockColumn.internalColumnEditor.maxLength = 10;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text is less than or equal to 10 characters' });
});

it('should return False when field is greater than a maxLength defined using exclusive operator', () => {
mockColumn.internalColumnEditor.maxLength = 10;
mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive';
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text is less than 10 characters' });
});

it('should return True when field is equal to the maxLength defined', () => {
mockColumn.internalColumnEditor.maxLength = 16;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: true, msg: '' });
});

it('should return True when field is equal to the maxLength defined and "operatorType" is set to "inclusive"', () => {
mockColumn.internalColumnEditor.maxLength = 16;
mockColumn.internalColumnEditor.operatorConditionalType = 'inclusive';
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: true, msg: '' });
});

it('should return False when field is equal to the maxLength defined but "operatorType" is set to "exclusive"', () => {
mockColumn.internalColumnEditor.maxLength = 16;
mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive';
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text is less than 16 characters' });
});

it('should return False when field is not between minLength & maxLength defined', () => {
mockColumn.internalColumnEditor.minLength = 0;
mockColumn.internalColumnEditor.maxLength = 10;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text length is between 0 and 10 characters' });
});

it('should return True when field is is equal to maxLength defined when both min/max values are defined', () => {
mockColumn.internalColumnEditor.minLength = 0;
mockColumn.internalColumnEditor.maxLength = 16;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text is 16 chars');

expect(validation).toEqual({ valid: true, msg: '' });
});

it('should return True when field is is equal to minLength defined when "operatorType" is set to "inclusive" and both min/max values are defined', () => {
mockColumn.internalColumnEditor.minLength = 4;
mockColumn.internalColumnEditor.maxLength = 15;
mockColumn.internalColumnEditor.operatorConditionalType = 'inclusive';
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('text');

expect(validation).toEqual({ valid: true, msg: '' });
});

it('should return False when field is equal to maxLength but "operatorType" is set to "exclusive" when both min/max lengths are defined', () => {
mockColumn.internalColumnEditor.minLength = 4;
mockColumn.internalColumnEditor.maxLength = 16;
mockColumn.internalColumnEditor.operatorConditionalType = 'exclusive';
editor = new AutoCompleteEditor(editorArguments);
const validation1 = editor.validate('text is 16 chars');
const validation2 = editor.validate('text');

expect(validation1).toEqual({ valid: false, msg: 'Please make sure your text length is between 4 and 16 characters' });
expect(validation2).toEqual({ valid: false, msg: 'Please make sure your text length is between 4 and 16 characters' });
});

it('should return False when field is greater than a maxValue defined', () => {
mockColumn.internalColumnEditor.maxLength = 10;
editor = new AutoCompleteEditor(editorArguments);
const validation = editor.validate('Task is longer than 10 chars');

expect(validation).toEqual({ valid: false, msg: 'Please make sure your text is less than or equal to 10 characters' });
});
});

Expand Down
Loading

0 comments on commit 318c70c

Please sign in to comment.