Skip to content
This repository has been archived by the owner on Jul 1, 2020. It is now read-only.

Commit

Permalink
Added custom validation #75
Browse files Browse the repository at this point in the history
- Added validation through custom user defined function
  • Loading branch information
ghiscoding committed Oct 30, 2015
1 parent 54cc7e1 commit da5e972
Show file tree
Hide file tree
Showing 13 changed files with 467 additions and 26 deletions.
2 changes: 1 addition & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ myApp.controller('CtrlValidationDirective', ['$q', '$scope', 'validationService'
// -- Controller to use Angular-Validation Directive with 2 forms
// on this page we will pre-validate the form and show all errors on page load
// ---------------------------------------------------------------
myApp.controller('Ctrl2forms', ['$scope', 'validationService', function ($scope, validationService) {
myApp.controller('Ctrl2forms', ['validationService', function (validationService) {
var vm = this; // use the ControllerAs alias syntax

// set the global options BEFORE any function declarations, we will prevalidate current form
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "angular-validation-ghiscoding",
"version": "1.4.10",
"version": "1.4.11",
"author": "Ghislain B.",
"description": "Angular-Validation Directive and Service (ghiscoding)",
"main": [
Expand Down
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
Angular-Validation change logs

1.4.11 (2015-10-29) Enhancement #75 - Added custom rules validation through custom functions. Fixed issue #76 - problem with ui-mask in directive.
1.4.10 (2015-10-12) Sanitized error messages. Fixed issue #69 - Stop when invalid characters typed on input[number].
1.4.9 (2015-10-05) Enhancement #57, #66, #67 - Added 3rd party addon validation (like ngTagsInput, Angular Multiselect, Dropdown multi-select, etc...)
1.4.8 (2015-09-12) Fixed issue #68 - Matching validation issue (password confirmation).
Expand Down
12 changes: 6 additions & 6 deletions dist/angular-validation.min.js

Large diffs are not rendered by default.

78 changes: 78 additions & 0 deletions more-examples/customJavascript/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use strict';

var myApp = angular.module('myApp', ['ghiscoding.validation', 'pascalprecht.translate', 'ui.bootstrap']);
// --
// configuration
myApp.config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}])
.config(['$translateProvider', function ($translateProvider) {
$translateProvider.useStaticFilesLoader({
prefix: '../../locales/validation/',
suffix: '.json'
});
// load English ('en') table on startup
$translateProvider.preferredLanguage('en').fallbackLanguage('en');
$translateProvider.useSanitizeValueStrategy('escapeParameters');
}]);

// --
// Directive
myApp.controller('CtrlDirective', ['validationService', function (validationService) {
var vmd = this;
vmd.model = {};

// use the validationService only to declare the controllerAs syntax
var vs = new validationService({ controllerAs: vmd });

vmd.myCustomValidation1 = function() {
// you can return a boolean for isValid or an objec (see the next function)
var isValid = (vmd.model.input1 === "abc");
return isValid;
}

vmd.myCustomValidation2 = function() {
// or you can return an object as { isValid: bool, message: msg }
var isValid = (vmd.model.input2 === "def");
return { isValid: isValid, message: 'Returned error from custom function.'};
}

vmd.submitForm = function() {
if(vs.checkFormValidity(vmd.form1)) {
alert('All good, proceed with submit...');
}
}
}]);

// --
// Service
myApp.controller('CtrlService', ['$scope', 'validationService', function ($scope, validationService) {
var vms = this;
vms.model = {};
//vms.model.input3 = 'a';
// use the validationService only to declare the controllerAs syntax
var vs = new validationService({ controllerAs: vms });

vs.setGlobalOptions({ scope: $scope })
.addValidator('input3', 'alpha|min_len:2|custom:vms.myCustomValidation3:alt=Alternate error message.|required')
.addValidator('input4', 'alpha|min_len:2|custom:vms.myCustomValidation4|required');

vms.myCustomValidation3 = function() {
// you can return a boolean for isValid or an objec (see the next function)
var isValid = (vms.model.input3 === "abc");
return isValid;
}

vms.myCustomValidation4 = function() {
// or you can return an object as { isValid: bool, message: msg }
var isValid = (vms.model.input4 === "def");
console.log(isValid);
return { isValid: isValid, message: 'Returned error from custom function.'};
}

vms.submitForm = function() {
if(new validationService().checkFormValidity(vms.form2)) {
alert('All good, proceed with submit...');
}
}
}]);
117 changes: 117 additions & 0 deletions more-examples/customJavascript/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<!DOCTYPE html>
<html ng-app="myApp" ng-strict-di ng-cloak="">
<head>
<meta charset="utf-8" />
<title>Angular-Validation with Custom Javascript function</title>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<link rel="stylesheet" href="../../style.css">
</head>

<body>
<div class="container">
<div ng-controller="CtrlDirective as vmd">
<h2>Example of Angular-Validation with Custom Javascript function</h2>

<h3>Directive</h3>
<div class="alert alert-danger alert-dismissable" ng-show="vmd.form1.$validationSummary.length &gt; 0">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h4><strong>ERRORS!</strong></h4>
<ul>
<li ng-repeat="item in vmd.form1.$validationSummary">{{ item.field }}: {{item.message}}</li>
</ul>
</div>

<form name="vmd.form1">
<div class="form-group">
<p>Type '<b>abc</b>' for a valid answer </p>
<label for="input1">Custom javascript Validation (error msg using alt:)</label>
<!-- defining the custom javascript function call by using `custom:` or `javascript:` -->
<input type="text" class="form-control"
name="input1"
ng-model="vmd.model.input1"
placeholder="alpha|min_len:2|custom:vmd.myCustomValidation1|required"
validation="alpha|min_len:2|custom:vmd.myCustomValidation1:alt=Alternate error message.|required" />
</div>
<br/>
<div class="form-group">
<p>Type '<b>def</b>' for a valid answer </p>
<label for="input2">Custom javascript Validation (error msg declared in custom function)</label>
<!-- same as previous but defined as `javascript` and error message is declared directly in the custom function -->
<input type="text" class="form-control"
name="input2"
ng-model="vmd.model.input2"
placeholder="alpha|min_len:2|custom:vmd.myCustomValidation2|required"
validation="alpha|min_len:2|custom:vmd.myCustomValidation2|required" />
</div>
<div class="form-actions">
<button type="submit" name="btn_ngDisabled1" class="btn btn-primary" ng-disabled="vmd.form1.$invalid" >{{ 'SAVE' | translate }} (ngDisabled)</button>
<button type="submit" name="btn_ngSubmit1" class="btn btn-primary" ng-click="vmd.submitForm()">{{ 'SAVE' | translate }} (ngSubmit)</button>
</div>
</form>
</div>

<hr/>

<div ng-controller="CtrlService as vms">
<h3>Service</h3>
<div class="alert alert-danger alert-dismissable" ng-show="vms.form2.$validationSummary.length &gt; 0">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<h4><strong>ERRORS!</strong></h4>
<ul>
<li ng-repeat="item in vms.form2.$validationSummary">{{ item.field }}: {{item.message}}</li>
</ul>
</div>

<form name="vms.form2">
<div class="form-group">
<p>Type '<b>abc</b>' for a valid answer </p>
<label for="input3">Custom javascript Validation (error msg using alt:)</label>
<!-- defining the custom javascript function call by using `custom:` or `javascript:` -->
<input type="text" class="form-control"
name="input3"
ng-model="vms.model.input3"
placeholder="alpha|min_len:2|custom:vms.myCustomValidation3|required" />
</div>
<br/>
<div class="form-group">
<p>Type '<b>def</b>' for a valid answer </p>
<label for="input4">Custom javascript Validation (error msg declared in custom function)</label>
<!-- same as previous but defined as `javascript` and error message is declared directly in the custom function -->
<input type="text" class="form-control"
name="input4"
ng-model="vms.model.input4"
placeholder="alpha|min_len:2|custom:vms.myCustomValidation4|required" />
</div>
<div class="form-actions">
<button type="submit" name="btn_ngDisabled2" class="btn btn-primary" ng-disabled="vms.form2.$invalid" >{{ 'SAVE' | translate }} (ngDisabled)</button>
<button type="submit" name="btn_ngSubmit2" class="btn btn-primary" ng-click="vms.submitForm()">{{ 'SAVE' | translate }} (ngSubmit)</button>
</div>
</form>
</div>
</div>

<!-- external librairies CDN -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular-route.js"></script>

<!-- angular-translate -->
<!-- Visit Angular-Translate https://github.com/PascalPrecht/angular-translate -->
<script src="../../vendors/angular-translate/angular-translate.min.js"></script>
<script src="../../vendors/angular-translate/angular-translate-loader-static-files.min.js"></script>

<!-- Angular-UI -->
<script src="https://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.2.js"></script>

<!-- Angular-Validation -->
<script type="text/javascript" src="../../dist/angular-validation.min.js"></script>
<!--
<script type="text/javascript" src="../../src/validation-directive.js"></script>
<script type="text/javascript" src="../../src/validation-service.js"></script>
<script type="text/javascript" src="../../src/validation-common.js"></script>
<script type="text/javascript" src="../../src/validation-rules.js"></script>
-->

<!-- my application -->
<script type="text/javascript" src="app.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "angular-validation-ghiscoding",
"version": "1.4.10",
"version": "1.4.11",
"author": "Ghislain B.",
"description": "Angular-Validation Directive and Service (ghiscoding)",
"main": "app.js",
Expand Down
5 changes: 3 additions & 2 deletions protractor/conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
// Spec patterns are relative to the current working directory when protractor is called
specs: [
'badInput_spec.js',
'custom_spec.js',
'mixed_validation_spec.js',
'angularUI_spec.js',
'dynamic_spec.js',
Expand All @@ -33,9 +34,9 @@
],
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 800000
defaultTimeoutInterval: 850000
},
allScriptsTimeout: 800000,
allScriptsTimeout: 850000,
seleniumAddress: 'http://localhost:4444/wd/hub',

// format the output when tests are run with Team City
Expand Down
132 changes: 132 additions & 0 deletions protractor/custom_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
describe('Angular-Validation Custom Javascript Validation Tests:', function () {
// global variables
var formElementNames = ['input1', 'input2', 'input3', 'input4'];
var errorMessages = [
'May only contain letters. Must be at least 2 characters. Field is required.',
'May only contain letters. Must be at least 2 characters. Field is required.',
'May only contain letters. Must be at least 2 characters. Field is required.',
'May only contain letters. Must be at least 2 characters. Field is required.'
];
var errorTooShort = [
'Must be at least 2 characters. Alternate error message.',
'Must be at least 2 characters. Returned error from custom function.',
'Must be at least 2 characters. Alternate error message.',
'Must be at least 2 characters. Returned error from custom function.'
];
var oneChar = ['a', 'd', 'a', 'd'];
var validInputTexts = ['abc', 'def', 'abc', 'def'];

describe('When choosing `more-examples` custom javascript', function () {
it('Should navigate to home page', function () {
browser.get('http://localhost/Github/angular-validation/more-examples/customJavascript/');

// Find the title element
var titleElement = element(by.css('h2'));
expect(titleElement.getText()).toEqual('Example of Angular-Validation with Custom Javascript function');
});

it('Should have multiple errors in Directive & Service validation summary', function () {
var itemRows = element.all(by.binding('message'));
var inputName;

for (var i = 0, j = 0, ln = itemRows.length; i < ln; i++) {
expect(itemRows.get(i).getText()).toEqual(defaultErrorMessages[i]);
}
});

it('Should check that both submit buttons are disabled', function() {
var elmSubmit1 = $('[name=btn_ngDisabled1]');
expect(elmSubmit1.isEnabled()).toBe(false);

var elmSubmit2 = $('[name=btn_ngDisabled2]');
expect(elmSubmit2.isEnabled()).toBe(false);
});

it('Should click, blur on each form elements and error message should display on each of them', function () {
for (var i = 0, ln = formElementNames.length; i < ln; i++) {
var elmInput = $('[name=' + formElementNames[i] + ']');
elmInput.click();
elmInput.sendKeys(protractor.Key.TAB);

var elmError = $('.validation-' + formElementNames[i]);
expect(elmError.getText()).toEqual(errorMessages[i]);
}
});

it('Should enter 1 character in all inputs and display minChar error message', function() {
for (var i = 0, ln = formElementNames.length; i < ln; i++) {
var elmInput = $('[name=' + formElementNames[i] + ']');
elmInput.click();
elmInput.sendKeys('a');

var elmError = $('.validation-' + formElementNames[i]);
expect(elmError.getText()).toEqual(errorTooShort[i]);
}
});

it('Should enter valid text and make error go away', function () {
for (var i = 0, ln = formElementNames.length; i < ln; i++) {
var elmInput = $('[name=' + formElementNames[i] + ']');
elmInput.click();
clearInput(elmInput);
elmInput.sendKeys(validInputTexts[i]);
elmInput.sendKeys(protractor.Key.TAB);

var elmError = $('.validation-' + formElementNames[i]);
expect(elmError.getText()).toEqual('');
}
});

it('Should have both validation summary empty', function() {
var itemRows = element.all(by.binding('message'));
expect(itemRows.count()).toBe(0);
});

it('Should check that both submit buttons are now enabled', function() {
var elmSubmit1 = $('[name=btn_ngDisabled1]');
expect(elmSubmit1.isEnabled()).toBe(true);

var elmSubmit2 = $('[name=btn_ngDisabled2]');
expect(elmSubmit2.isEnabled()).toBe(true);
});

it('Should navigate to home page', function () {
browser.get('http://localhost/Github/angular-validation/more-examples/customJavascript/');

// Find the title element
var titleElement = element(by.css('h2'));
expect(titleElement.getText()).toEqual('Example of Angular-Validation with Custom Javascript function');
});

it('Should click on both ngSubmit buttons', function() {
var btnNgSubmit1 = $('[name=btn_ngSubmit1]');
btnNgSubmit1.click();

var btnNgSubmit2 = $('[name=btn_ngSubmit2]');
btnNgSubmit2.click();
});

it('Should show error message on each inputs', function () {
for (var i = 0, ln = formElementNames.length; i < ln; i++) {
var elmInput = $('[name=' + formElementNames[i] + ']');
elmInput.click();
elmInput.sendKeys(protractor.Key.TAB);

var elmError = $('.validation-' + formElementNames[i]);
expect(elmError.getText()).toEqual(errorMessages[i]);
}
});

});
});

/** From a given input name, clear the input
* @param string input name
*/
function clearInput(elem) {
elem.getAttribute('value').then(function (text) {
var len = text.length
var backspaceSeries = Array(len+1).join(protractor.Key.BACK_SPACE);
elem.sendKeys(backspaceSeries);
})
}
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#Angular Validation (Directive / Service)
`Version: 1.4.10`
`Version: 1.4.11`
### Form validation after user inactivity of default 1sec. (customizable timeout)

Forms Validation with Angular made easy! Angular-Validation is an angular directive/service with locales (languages) with a very simple approach of defining your `validation=""` directly within your element to validate (input, textarea, etc) and...that's it!!! The directive/service will take care of the rest!
Expand Down Expand Up @@ -80,6 +80,7 @@ All the documentation has been moved to the Wiki section, see the [github wiki](
* [DisplayErrorTo](https://github.com/ghiscoding/angular-validation/wiki/Bootstrap-Input-Groups-Wrapping)
* [Isolated Scope](https://github.com/ghiscoding/angular-validation/wiki/Isolated-Scope)
* [PreValidate Form (on page load)](https://github.com/ghiscoding/angular-validation/wiki/PreValidate-Form-(on-page-load))
* [Custom Validation function](https://github.com/ghiscoding/angular-validation/wiki/Custom-Validation-functions)
* [Remote Validation (AJAX)](https://github.com/ghiscoding/angular-validation/wiki/Remote-Validation-(AJAX))
* [Remove a Validator](https://github.com/ghiscoding/angular-validation/wiki/Remove-Validator-from-Element)
* [Reset Form](https://github.com/ghiscoding/angular-validation/wiki/Reset-Form)
Expand Down
Loading

0 comments on commit da5e972

Please sign in to comment.