Added custom validation option to xosField component
diff --git a/views/ngXosLib/xosHelpers/spec/ui/custom-validator.test.js b/views/ngXosLib/xosHelpers/spec/ui/custom-validator.test.js
new file mode 100644
index 0000000..76f41a9
--- /dev/null
+++ b/views/ngXosLib/xosHelpers/spec/ui/custom-validator.test.js
@@ -0,0 +1,107 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+ 'use strict';
+
+ describe('The xos.helper module', function () {
+ describe('The xosCustomValidator directive', () => {
+ let element, scope, isolatedScope, rootScope, compile, form, input;
+ const compileElement = (el) => {
+ element = el;
+
+ if(!scope){
+ scope = rootScope.$new();
+ }
+ if(angular.isUndefined(element)){
+ element = angular.element(`
+ <form name="form">
+ <input name="testInput" type="text" ng-model="value" xos-custom-validator custom-validator="validator"/>
+ </form>
+ `);
+ }
+ compile(element)(scope);
+ scope.$digest();
+ input = $(element).find('input');
+ isolatedScope = angular.element(input).isolateScope();
+ form = scope.form;
+ };
+
+ beforeEach(module('xos.helpers'));
+
+ beforeEach(inject(function ($compile, $rootScope) {
+ compile = $compile;
+ rootScope = $rootScope;
+ }));
+
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.validator = 'validator';
+ scope.value = '';
+ compileElement();
+ });
+
+ it('should bind the validator', () => {
+ expect(isolatedScope.fn).toEqual('validator');
+ });
+
+ describe('given a validator function', () => {
+
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.value = '';
+ scope.validator = (model) => angular.equals(model, 'test');
+ spyOn(scope, 'validator').and.callThrough();
+ compileElement();
+ });
+
+ it('should call the validator function on value change', () => {
+ form.testInput.$setViewValue('something');
+ scope.$digest();
+ expect(scope.validator).toHaveBeenCalledWith('something');
+ expect(scope.value).toEqual('something');
+ });
+
+ it('should set the field invalid', () => {
+ form.testInput.$setViewValue('something');
+ scope.$digest();
+ expect(scope.validator).toHaveBeenCalledWith('something');
+ expect(input).toHaveClass('ng-invalid');
+ expect(input).toHaveClass('ng-invalid-custom-validation');
+ });
+
+ it('should set the field valid', () => {
+ form.testInput.$setViewValue('test');
+ scope.$digest();
+ expect(scope.validator).toHaveBeenCalledWith('test');
+ expect(input).not.toHaveClass('ng-invalid');
+ expect(input).not.toHaveClass('ng-invalid-custom-validation');
+ });
+
+ describe('if the validation function return an array', () => {
+
+ beforeEach(() => {
+ scope = rootScope.$new();
+ scope.value = '';
+ scope.validator = (model) => {
+ return ['randomTest', angular.equals(model, 'test')];
+ };
+ spyOn(scope, 'validator').and.callThrough();
+ compileElement();
+ });
+
+ it('should set the field invalid', () => {
+ form.testInput.$setViewValue('something');
+ scope.$digest();
+ expect(scope.validator).toHaveBeenCalledWith('something');
+ expect(input).toHaveClass('ng-invalid');
+ expect(input).toHaveClass('ng-invalid-random-test');
+ });
+ });
+ });
+ });
+ });
+})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/spec/ui/field.test.js b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
index 8b32585..8a02d4d 100644
--- a/views/ngXosLib/xosHelpers/spec/ui/field.test.js
+++ b/views/ngXosLib/xosHelpers/spec/ui/field.test.js
@@ -7,24 +7,23 @@
(function () {
'use strict';
- let element, scope, isolatedScope, rootScope, compile;
- const compileElement = (el) => {
- element = el;
-
- if(!scope){
- scope = rootScope.$new();
- }
- if(angular.isUndefined(element)){
- element = angular.element('<xos-field name="name" field="field" ng-model="ngModel"></xos-field>');
- }
- compile(element)(scope);
- scope.$digest();
- isolatedScope = element.isolateScope().vm;
- };
-
describe('The xos.helper module', function(){
describe('The xosField component', () => {
+ let element, scope, isolatedScope, rootScope, compile;
+ const compileElement = (el) => {
+ element = el;
+
+ if(!scope){
+ scope = rootScope.$new();
+ }
+ if(angular.isUndefined(element)){
+ element = angular.element('<xos-field name="name" field="field" ng-model="ngModel"></xos-field>');
+ }
+ compile(element)(scope);
+ scope.$digest();
+ isolatedScope = element.isolateScope().vm;
+ };
beforeEach(module('xos.helpers'));
@@ -93,7 +92,9 @@
scope.field = {
label: 'Label',
type: 'text',
- validators: {}
+ validators: {
+ custom: 'fake'
+ }
};
scope.ngModel = 'label';
compileElement();
@@ -102,6 +103,12 @@
it('should print a text field', () => {
expect($(element).find('[name="label"]')).toHaveAttr('type', 'text');
});
+
+ it('should attach the custom validator directive', () => {
+ let input = $(element).find('[name="label"]');
+ expect(input).toHaveAttr('xos-custom-validator');
+ expect(input).toHaveAttr('custom-validator', 'vm.field.validators.custom || null');
+ });
});
describe('when a option is selected in dropdown', () => {
@@ -266,7 +273,6 @@
});
});
- // NOTE not sure why this tests are failing
describe('when validation options are passed', () => {
let input;
describe('given a a text field', () => {
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
index fa02dbb..2719bb3 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/field/field.component.js
@@ -153,6 +153,7 @@
template: `
<label ng-if="vm.field.type !== 'object'">{{vm.field.label}}</label>
<input
+ xos-custom-validator custom-validator="vm.field.validators.custom || null"
ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object' && vm.field.type !== 'select'"
type="{{vm.field.type}}"
name="{{vm.name}}"
@@ -234,5 +235,45 @@
this.isEmptyObject = o => o ? Object.keys(o).length === 0 : true;
}
}
+ })
+
+/**
+ * @ngdoc directive
+ * @name xos.uiComponents.directive:xosCustomValidator
+ * @restrict A
+ * @description The xosCustomValidator directive.
+ * This component apply a custom validation function
+ * @param {function} customValidator The function that execute the validation.
+ *
+ * You should do your validation here and return true | false,
+ * or alternatively you can return an array [errorName, true|false]
+ */
+ .directive('xosCustomValidator', function(){
+ return {
+ restrict: 'A',
+ scope: {
+ fn: '=customValidator'
+ },
+ require: 'ngModel',
+ link: function(scope, element, attr, ctrl){
+ if(!angular.isFunction(scope.fn)){
+ return;
+ }
+
+ function customValidatorWrapper(ngModelValue) {
+ const valid = scope.fn(ngModelValue);
+ if(angular.isArray(valid)){
+ // ES6 spread rocks over fn.apply()
+ ctrl.$setValidity(...valid);
+ }
+ else{
+ ctrl.$setValidity('customValidation', valid);
+ }
+ return ngModelValue;
+ }
+
+ ctrl.$parsers.push(customValidatorWrapper);
+ }
+ };
});
})();
\ No newline at end of file
diff --git a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
index 1706483..89ef192 100644
--- a/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
+++ b/views/ngXosLib/xosHelpers/src/ui_components/dumbComponents/form/form.component.js
@@ -46,7 +46,11 @@
maxlength: number,
required: boolean,
min: number,
- max: number
+ max: number,
+ custom: (value) => {
+ // do your validation here and return true | false
+ // alternatively you can return an array [errorName, true|false]
+ }
* }
* }
* }