├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── Gruntfile.js ├── README.md ├── bower.json ├── demo ├── app.js └── index.html ├── dist ├── angular-validator.js └── angular-validator.min.js ├── karma.conf.js ├── package.json ├── src └── angular-validator.js └── test └── angular-validator-spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | npm-debug.log -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false # use container-based virtualization environment 2 | language: node_js 3 | node_js: 4 | - "6" # Node.js LTS maintained until April 2019, https://github.com/nodejs/lts 5 | - "node" # latest stable Node.js release 6 | before_script: 7 | - export DISPLAY=:99.0 8 | - sh -e /etc/init.d/xvfb start 9 | - 'npm install -g bower grunt-cli' 10 | - 'bower install --config.interactive=false' 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | Thanks for wanting to contribute. Please follow the instructions below. 3 | 4 | 5 | ## Getting started 6 | 1. Clone the repository 7 | 2. Run `bower install` in the repository directory 8 | 3. Run `npm install` in the repository directory 9 | 4. Run `grunt serve` to start serving the demo on `http://localhost:9001/demo/` 10 | 11 | 12 | ## Before creating a pull request 13 | 1. Make sure you add tests to `/test/angular-validator-spec.js` that test your changes. To run tests `grunt test` 14 | 2. If appropriate update the README to reflect your changes. 15 | 3. Run `grunt build` to minify and create a `dist` version of your changes 16 | 4. If appropriate update the demo in /demo/ 17 | 5. The project maintainer will update the Plunker demo that is linked in README.md if needed. -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*jslint node: true */ 2 | 'use strict'; 3 | 4 | var pkg = require('./package.json'); 5 | 6 | module.exports = function(grunt) { 7 | 8 | // Grunt Config 9 | grunt.initConfig({ 10 | pkg: grunt.file.readJSON('package.json'), 11 | 12 | connect: { 13 | server: { 14 | options: { 15 | port: 9001, 16 | base: '.' 17 | } 18 | } 19 | }, 20 | concat: { 21 | "options": { 22 | "separator": ";" 23 | }, 24 | "build": { 25 | "src": "src/*.js", 26 | "dest": "dist/angular-validator.js" 27 | } 28 | }, 29 | ngAnnotate: { 30 | main: { 31 | src: 'dist/angular-validator.js', 32 | dest: 'dist/angular-validator.js' 33 | }, 34 | }, 35 | uglify: { 36 | dist: { 37 | src: "dist/angular-validator.js", 38 | dest: "dist/angular-validator.min.js" 39 | } 40 | }, 41 | jshint: { 42 | files: ['Gruntfile.js', 'src/*.js'], 43 | options: { 44 | jshintrc: true 45 | } 46 | }, 47 | watch: { 48 | files: ['src/*.js', 'demo/*.*'], 49 | tasks: ['build'], 50 | options: { 51 | livereload: true 52 | } 53 | }, 54 | karma: { 55 | options: { 56 | configFile: 'karma.conf.js' 57 | }, 58 | build: { 59 | singleRun: true, 60 | autoWatch: true 61 | }, 62 | debug: { 63 | singleRun: false, 64 | autoWatch: true, 65 | browsers: ['Chrome'] 66 | }, 67 | travis: { 68 | singleRun: true, 69 | autoWatch: false, 70 | browsers: ['Firefox'] 71 | }, 72 | dev: { 73 | autoWatch: true 74 | } 75 | } 76 | }); 77 | 78 | grunt.loadNpmTasks('grunt-contrib-watch'); 79 | grunt.loadNpmTasks('grunt-contrib-connect'); 80 | grunt.loadNpmTasks('grunt-ng-annotate'); 81 | 82 | // Load the plugin that provides the "jshint" task. 83 | grunt.loadNpmTasks('grunt-contrib-jshint'); 84 | 85 | // Load the plugin that provides the "concat" task. 86 | grunt.loadNpmTasks('grunt-contrib-concat'); 87 | 88 | // Load the plugin that provides the "uglify" task. 89 | grunt.loadNpmTasks('grunt-contrib-uglify'); 90 | grunt.loadNpmTasks('grunt-karma'); 91 | 92 | 93 | 94 | // Register Task 95 | grunt.registerTask('serve', ['connect', 'watch']); 96 | grunt.registerTask('build', ['concat', 'ngAnnotate', 'uglify', 'karma:build']); 97 | grunt.registerTask('test', ['karma:build', ]); 98 | grunt.registerTask('test-debug', ['karma:debug']); 99 | grunt.registerTask('travis', ['karma:travis']); 100 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular-Validator 2 | [![Build Status](https://travis-ci.org/turinggroup/angular-validator.png)](https://travis-ci.org/turinggroup/angular-validator) 3 | 4 | Angular-Validator is an easy to use, powerful and lightweight AngularJS validation directive. 5 | 6 | ## Demo 7 | [Check out the demo!](http://plnkr.co/edit/XbDYKrM2QUf8g1ubTHma?p=preview) 8 | 9 | ## Features 10 | * Validate using regex, HTML5, or custom validation functions. 11 | * Works seamlessly with all native AngularJS validation directives and native HTML5 validation attributes. 12 | * Supports custom validation message templates and placement using Angular's native `ngMessages` directive. 13 | * Choose when to validate elements, on per-element basis. Choose between on form `submission`, `blur` or `dirty`(change). 14 | * All validation states and validation messages are accessible through `$scope.yourFormName.elementName`. 15 | * Prevents submission if the form is invalid 16 | * Built in `reset()` form method 17 | * Supports multi-field dependent validation (one field depends on another such as password matching) 18 | * Works with Bootstrap out of the box (although Bootstrap is not required) 19 | * Optionally adds `.has-error` classes to invalid form and message message elements so you don't have to. 20 | * Supports form invalid message service where manage invalid messages in one place and save code in HTML 21 | 22 | ## Why? 23 | Despite Angular's awesomeness, validation in Angular is still annoying. Surprisingly there are no seamless, user-friendly, well written Angular validation tools. Unlike other Angular validation tools, Angular-Validator works with out-of-the-box Angular and HTML5 validation, directives and attributes, allowing your forms to work well with the browser and other Javascript code. 24 | 25 | ## Installation 26 | 1. Using bower: `bower install tg-angular-validator`. 27 | 2. Include `angular-validator.min.js`. 28 | 3. Add `angularValidator` as a dependency of your Angular module. 29 | 30 | ## Usage 31 | 32 | **Basic usage for required fields** 33 | ``` 34 | 38 | ``` 39 | 40 | **Usage with a custom validator function** 41 | ``` 42 | 46 | ``` 47 | 48 | **Usage with validation on blur** 49 | ``` 50 | 55 | ``` 56 | 57 | **Usage with validation on dirty** 58 | ``` 59 | 64 | ``` 65 | 66 | **Usage with custom validator literal** 67 | ``` 68 | 72 | ``` 73 | 74 | **Usage with REGEX and required** 75 | ``` 76 | 81 | ``` 82 | 83 | **Usage with custom error message text** 84 | ``` 85 | 92 | ``` 93 | 94 | **Usage with conditional invalid/required message text** 95 | ``` 96 | 103 | ``` 104 | * Note that the validator and the message function do not need to be the same function. If you choose to make them the same function make sure to return `true` on valid input. 105 | 106 | **Usage without auto-generated error label** 107 | 108 | ``` 109 | 115 | ``` 116 | 117 | Use `angular-validator-quiet` on an element to prevent the auto-generation of new DOM element `label` after this inputs. You then have complete control over the location and classes used to show the error messages. 118 | 119 | **Setting up the form** 120 | ``` 121 |
122 | .... 123 | .... 124 | 125 |
126 | ``` 127 | Use `angular-validator-submit` to specify the function to be called when the form is submitted. Note that the function is not called if the form is invalid. 128 | 129 | 130 | **Use form invalid message service** 131 | ``` 132 |
133 | 137 |
138 | ``` 139 | Use `invalid-message` on form element to provide the name of the service in which invalid messages are managed. You need to provide a `message` function in your service, which returns the messages you defined. Form invalid message service saves repetitive code in HTML because you do not need to use invalid-message attribute on every field. Please see the demo for examples. 140 | 141 | **Usage form without auto-generated error label** 142 | 143 | ``` 144 |
145 | ``` 146 | 147 | Use `angular-validator-quiet` on form element to prevent the auto-generation of new DOM element `label` after all of this forms inputs. 148 | 149 | **Resetting the form** 150 | ``` 151 | myFormName.reset() 152 | ``` 153 | *You need to include a `name` attribute on the form to use this.* 154 | 155 | 156 | **Validity API** 157 | Uses standard Angular `$valid` and `$invalid` properties so that it can work with core angular and third party libraries! 158 | ``` 159 | formName.$invalid 160 | formName.$valid 161 | elementName.$valid 162 | elementName.$invalid 163 | elementName.$angularValidator 164 | ``` 165 | 166 | ## FAQ 167 | **It's not working!?** 168 | Make sure you have assigned a unique name to each form element as well as the form itself. Make sure you have properly followed the installation instructions. 169 | 170 | **Why pass value to custom validator functions?** 171 | Passing the value to the custom validator function allows the function to be easier to test. 172 | 173 | **How do I display success messages/classes?** 174 | The library does not currently support success classes and messages. Feel free to contribute. 175 | 176 | **What if I want error messages to display before the user types anything?** 177 | You are using the wrong library. 178 | 179 | **What if I want to disable the submit button if the form is invalid?** 180 | You can add `ng-disabled="myForm.$invalid"` on the submit button. 181 | 182 | 183 | ## CONTRIBUTING 184 | See CONTRIBUTING.md 185 | 186 | ## License 187 | MIT 188 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tg-angular-validator", 3 | "version": "1.2.10", 4 | "authors": [ 5 | "Zohar Jackson " 6 | ], 7 | "main": "./dist/angular-validator.js", 8 | "description": "An easy to use, powerful and lightweight AngularJS validation directive.", 9 | "keywords": [ 10 | "AngularJS", 11 | "validation", 12 | "angular validation", 13 | "form validation", 14 | "angular", 15 | "validator", 16 | "client-side" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "src", 25 | "demo", 26 | "bower.json", 27 | "gruntfile.js", 28 | "package.json", 29 | "README.md", 30 | "karma.conf.js" 31 | ], 32 | "dependencies": { 33 | "angular": ">=1.3.0", 34 | "jquery": "~2.1.4" 35 | }, 36 | "devDependencies": { 37 | "angular-mocks": "^1.6.2", 38 | "angular-messages": "^1.6.2" 39 | }, 40 | "homepage": "https://github.com/turinggroup/angular-validator" 41 | } 42 | -------------------------------------------------------------------------------- /demo/app.js: -------------------------------------------------------------------------------- 1 | angular.module('angular-validator-demo', ['angularValidator', 'ngMessages']); 2 | 3 | 4 | angular.module('angular-validator-demo').controller('DemoCtrl', function($scope) { 5 | 6 | $scope.submitMyForm = function() { 7 | alert("Form submitted"); 8 | }; 9 | 10 | 11 | $scope.myCustomValidator = function(text) { 12 | return true; 13 | }; 14 | 15 | 16 | $scope.anotherCustomValidator = function(text) { 17 | if (text === "rainbow") { 18 | return true; 19 | } else return "type in 'rainbow'"; 20 | }; 21 | 22 | 23 | $scope.passwordValidator = function(password) { 24 | 25 | if (!password) { 26 | return; 27 | } 28 | else if (password.length < 6) { 29 | return "Password must be at least " + 6 + " characters long"; 30 | } 31 | else if (!password.match(/[A-Z]/)) { 32 | return "Password must have at least one capital letter"; 33 | } 34 | else if (!password.match(/[0-9]/)) { 35 | return "Password must have at least one number"; 36 | } 37 | 38 | return true; 39 | }; 40 | }).factory('customMessage', function () { 41 | // invalid message service with message function 42 | return { 43 | // scopeElementModel is the object in scope version, element is the object in DOM version 44 | message: function (scopeElementModel, element) { 45 | var errors = scopeElementModel.$error; 46 | if (errors.maxlength) { 47 | // be careful with the quote 48 | return "'Should be no longer than " + element.attributes['ng-maxlength'].value + " characters!'"; 49 | } else { 50 | // default message 51 | return "'This field is invalid!'"; 52 | } 53 | } 54 | }; 55 | }); -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Angular-Validator Demo 4 | 5 | 8 | 9 | 10 | 11 |
12 |

Angular-Validator Demo

13 | https://github.com/turinggroup/angular-validator 14 |
15 | 16 |

Choose when to validate:

17 |
18 | 19 |
20 |
29 |
30 |
31 | 32 |
33 |
42 |
43 |
44 | 45 |
46 |
54 |
55 | 56 |
57 |

Different types of validation:

58 | 59 |
60 | 61 |
62 |
69 |
70 |
71 | 72 |
73 |
81 |
82 |
83 | 84 |
85 |
94 |
95 |
96 | 97 |
98 |
106 |
107 |
108 | 109 |

Password validation and password matching example

110 |
111 | 112 |
113 |
121 |
122 |
123 | 124 |
125 |
133 |
134 |
135 |
136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 | 144 |
145 |

Form invalid message:

146 |
147 | 148 |
149 |
156 |
157 |
158 |

Field invalid message hides form invalid message

159 |
160 | 161 |
162 |
170 |
171 |
172 |
173 |
174 | 175 | 176 |
177 |
178 |
179 | 180 |
181 |

Using Field angular-validator-quiet (with angular-messages)

182 |
183 | 184 |
185 |
192 |
193 |
"Required" message with manual template
194 |
"Max Length" message with manual template
195 |
196 |
197 |
198 | 199 |
200 |
206 |
207 |
208 |
209 |
210 | 211 | 212 |
213 |
214 | 215 |
216 | 217 |
218 |

Using Form angular-validator-quiet (with angular-messages)

219 |
220 | 221 |
222 |
228 |
229 |
"Required" message with manual template
230 |
"Max Length" message with manual template
231 |
232 |
233 |
234 | 235 |
236 |
242 |
243 |
"Required" message with manual template
244 |
"Max Length" message with manual template
245 |
246 |
247 |
248 |
249 |
250 | 251 | 252 |
253 |
254 | 255 |
256 | 257 |
258 |

Scope Sneak Peak 259 |

260 |

Form valid: {{myForm.$valid}}

261 |

First Name valid: {{myForm.firstName.$valid}}

262 |

Email Valid: {{myForm.emailAddress.$valid}}

263 |

Password Valid: {{myForm.password.$valid}} {{form.password}}

264 |

Regex Valid: {{myForm.regex.$valid}}

265 |

Form submitted: {{myForm.submitted}}

266 | 267 |
268 | 269 | 270 | 271 | 272 | 273 | 274 | -------------------------------------------------------------------------------- /dist/angular-validator.js: -------------------------------------------------------------------------------- 1 | angular.module('angularValidator', []); 2 | 3 | angular.module('angularValidator').directive('angularValidator', ['$injector', '$parse', '$compile', 4 | function($injector, $parse, $compile) { 5 | return { 6 | restrict: 'A', 7 | link: function(scope, element, attrs, fn) { 8 | var getRandomInt = function() { 9 | return Math.floor((Math.random() * 100000)); 10 | }; 11 | 12 | // For this directive to work the form needs a name attribute as well as every input element. 13 | // This function will add names where missing 14 | var need_to_recompile = false; 15 | 16 | // Iterate through all the children of the form element and add a `name` attribute to the ones 17 | // that are missing it. 18 | angular.forEach(element.find('input,select,textarea'), function(child_element) { 19 | child_element = $(child_element); 20 | if (!child_element.attr('name')) { 21 | child_element.attr('name', getRandomInt()); 22 | console.log('WARNING! AngularValidator -> One of your form elements(,