├── .gitignore ├── CHANGELOG.md ├── Gruntfile.coffee ├── LICENSE ├── README.md ├── bower.json ├── karma.conf.js ├── package.json ├── src ├── showErrors.coffee ├── showErrors.js └── showErrors.min.js └── test ├── helpers.coffee ├── helpers.js ├── showErrors.spec.coffee └── showErrors.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 2.3.0 2 | 3 | * Bug Fixes 4 | * reverted the commit in v2.2.0 that no longer required inputs to have the form-control class. This broke select boxes. 5 | 6 | ### 2.2.0 7 | 8 | * Enhancements 9 | * Added option to skip the form group check. Thanks @lukaselmer 10 | * Allow input-group instead of form-group class. Thanks @morgenes 11 | * Works with inputs without the form-control class (helps it work with radio and checkbox controls). Thanks @Kheldar 12 | 13 | ### 2.1.0 14 | 15 | * Enhancements 16 | * Using `$interpolate` to retrieve the name of the input element. This allows the directive to work with interpolated form names. Thanks @cherrydev and @Templarian 17 | 18 | ### 2.0.0 19 | 20 | * Breaking Changes 21 | * Added a more specific selector query for the input element. The input element must now also have the 'form-control' class associated with it. Thanks @martindederer 22 | 23 | * Enhancements 24 | * Added `trigger` option to provide a custom trigger to validate the value. By default the trigger is the `blur` event. Thanks @Templarian 25 | 26 | ### 1.1.0 27 | 28 | * Enhancements 29 | * Added `showSuccess` option 30 | 31 | * Bug Fixes 32 | * Does not throw an undefined error when the form is dynamically created. Thanks @murphyalexandre 33 | 34 | ### 1.0.4 35 | 36 | * Bug Fixes 37 | * Using inline array notation to allow the js file to be minified 38 | 39 | ### 1.0.3 40 | 41 | * Bug Fixes 42 | * Fixed edge case where the error class was not removed correctly after manually checking validation. 43 | 44 | ### 1.0.2 45 | 46 | * refactorings 47 | * checking if name attribute exists in the link function instead of the compile function 48 | -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (grunt) -> 2 | 3 | grunt.initConfig 4 | coffee: 5 | options: 6 | bare: false 7 | compile: 8 | files: 9 | 'src/showErrors.js': 'src/showErrors.coffee' 10 | 'test/showErrors.spec.js': 'test/showErrors.spec.coffee' 11 | 'test/helpers.js': 'test/helpers.coffee' 12 | pkg: grunt.file.readJSON('package.json') 13 | uglify: 14 | options: 15 | banner: '/*! <%= pkg.name %> (version <%= pkg.version %>) <%= grunt.template.today("yyyy-mm-dd") %> */\n' 16 | build: 17 | src: 'src/showErrors.js' 18 | dest: 'src/showErrors.min.js' 19 | watch: 20 | files: [ 21 | 'src/showErrors.coffee' 22 | 'test/showErrors.spec.coffee' 23 | ] 24 | tasks: 'default' 25 | karma: 26 | files: ['src/showErrors.js', 'test/showErrors.spec.js'] 27 | tasks: ['karma:unit:run'] 28 | karma: 29 | unit: 30 | configFile: 'karma.conf.js' 31 | singleRun: true 32 | continuous: 33 | configFile: 'karma.conf.js' 34 | background: true 35 | 36 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks) 37 | 38 | grunt.registerTask 'default', ['coffee', 'uglify', 'karma:unit'] 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013-2014 Paul Yoder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Angular Bootstrap Show Errors 2 | ============================= 3 | 4 | An Angular directive for Bootstrap 3 that intelligently applies the 'has-error' class to invalid form fields. 5 | 6 | See the [Bootstrap Form Validation Done Right in AngularJS](http://blog.yodersolutions.com/bootstrap-form-validation-done-right-in-angularjs?utm_source=github&utm_medium=readme&utm_campaign=code) blog post to read about the benefits of using this directive. 7 | 8 | Installation 9 | --- 10 | With Bower 11 | 12 | bower install angular-bootstrap-show-errors 13 | 14 | Manually 15 | 16 | Copy the `src/showErrors.js` or `src/showErrors.min.js` file into your project. 17 | 18 | Quick Start 19 | --- 20 | 1. Include the `ui.bootstrap.showErrors` module in your Angular app 21 | ```javascript 22 | angular.module('yourApp', ['ui.bootstrap.showErrors']); 23 | ``` 24 | 25 | 2. Add the `show-errors` attribute on the div element that contains the `form-group` class 26 | ```html 27 |
28 |
29 | 30 |
31 |
32 | ``` 33 | 34 | 3. If you want to avoid the extra bottom margin of `form-group`, you can use `input-group`. 35 | ```html 36 |
37 |
38 | 39 |
40 |
41 | ``` 42 | 43 | Force Validity Check 44 | --- 45 | By default this directive doesn't check the validity until the user tabs off the input element. However, there are times you want to show invalid form elements even if the user has not tabbed off. (e.g. before saving the form) 46 | 47 | To force the validity check, broadcast the `show-errors-check-validity` event. 48 | 49 | #### Example 50 | 51 | 52 | ```html 53 |
54 |
55 | 56 |
57 | 58 |
59 | ``` 60 | 61 | ```javascript 62 | $scope.save = function() { 63 | $scope.$broadcast('show-errors-check-validity'); 64 | 65 | if ($scope.userForm.$valid) { 66 | // save the user 67 | } 68 | } 69 | ``` 70 | 71 | Reset 72 | --- 73 | If you have functionality to reset your form, you can broadcast the 'show-errors-reset' event to remove any errors on the form elements. 74 | 75 | #### Example 76 | 77 | ```html 78 |
79 |
80 | 81 |
82 | Reset 83 |
84 | ``` 85 | 86 | ```javascript 87 | $scope.reset = function() { 88 | $scope.$broadcast('show-errors-reset'); 89 | } 90 | ``` 91 | 92 | Show Valid Entries 93 | --- 94 | It's also possible to let the user know when they have entered valid values by applying the 'show-success' class that Bootstrap provides. 95 | You can either apply this globally or on an element by element basis. 96 | 97 | ##### Globally 98 | The following example shows how to show valid values on every input that uses the showErrors directive. 99 | 100 | ```javascript 101 | app = angular.module('yourApp', ['ui.bootstrap.showErrors']); 102 | app.config(['showErrorsConfigProvider', function(showErrorsConfigProvider) { 103 | showErrorsConfigProvider.showSuccess(true); 104 | }]); 105 | ``` 106 | 107 | ##### By Input Element 108 | If you only want to show valid values on specific inputs, then you can pass in the `{ showSuccess: true }` option like the example below shows. 109 | 110 | ```html 111 |
112 |
113 | 114 |
115 |
116 | ``` 117 | 118 | Skip Form Group Check 119 | --- 120 | If your HTML code doesn't have a form-group class, the form group check can be skipped: 121 | 122 | ```html 123 |
124 |
125 | 126 |
127 |
128 | ``` 129 | 130 | Custom Trigger 131 | --- 132 | By default, the validation is not performed until the `blur` event is trigger on the input 133 | element. However, there are some scenarios where this is not desirable, so it's possible to 134 | override this with the `trigger` option. 135 | 136 | ##### By Input Element 137 | ```html 138 |
139 |
140 | 141 |
142 |
143 | ``` 144 | 145 | ##### Globally 146 | ```javascript 147 | app = angular.module('yourApp', ['ui.bootstrap.showErrors']); 148 | app.config(['showErrorsConfigProvider', function(showErrorsConfigProvider) { 149 | showErrorsConfigProvider.trigger('keypress'); 150 | }]); 151 | ``` 152 | 153 | ## Development 154 | 155 | ### Install Development Dependencies 156 | Before you begin development, you will need to install the required node modules and bower components. To do 157 | so, open a terminal window in the project directory and run the following commands. 158 | ``` 159 | npm install 160 | bower install 161 | ``` 162 | 163 | ### Compile and Run the Unit Tests 164 | Just type `grunt` in the command line to compile and run the karma unit tests once. 165 | 166 | If you want to have grunt watch for any file changes and automatically compile and run the karma 167 | unit tests, then run the following command: 168 | ``` 169 | grunt karma:continuous:start watch 170 | ``` 171 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bootstrap-show-errors", 3 | "version": "2.3.0", 4 | "authors": [ 5 | "Paul Yoder " 6 | ], 7 | "description": "An Angular directive for Bootstrap to intelligently show form validation errors", 8 | "main": "src/showErrors.js", 9 | "keywords": [ 10 | "angular", 11 | "bootstrap", 12 | "directive", 13 | "validation" 14 | ], 15 | "license": "MIT", 16 | "homepage": "https://github.com/paulyoder/angular-bootstrap-show-errors", 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "test" 22 | ], 23 | "dependencies": { 24 | "angular": "*" 25 | }, 26 | "devDependencies": { 27 | "angular": "1.2.0", 28 | "angular-mocks": "1.2.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Oct 31 2013 11:47:14 GMT-0500 (Central Daylight Time) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path, that will be used to resolve files and exclude 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | frameworks: ['jasmine'], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'bower_components/angular/angular.js', 18 | 'bower_components/angular-mocks/angular-mocks.js', 19 | 'src/showErrors.js', 20 | 'test/helpers.js', 21 | 'test/showErrors.spec.js' 22 | ], 23 | 24 | 25 | // list of files to exclude 26 | exclude: [ 27 | 28 | ], 29 | 30 | 31 | // test results reporter to use 32 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 33 | reporters: ['progress'], 34 | 35 | 36 | // web server port 37 | port: 9876, 38 | 39 | 40 | // enable / disable colors in the output (reporters and logs) 41 | colors: true, 42 | 43 | 44 | // level of logging 45 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 46 | logLevel: config.LOG_INFO, 47 | 48 | 49 | // enable / disable watching file and executing tests whenever any file changes 50 | autoWatch: false, 51 | 52 | 53 | // Start these browsers, currently available: 54 | // - Chrome 55 | // - ChromeCanary 56 | // - Firefox 57 | // - Opera (has to be installed with `npm install karma-opera-launcher`) 58 | // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) 59 | // - PhantomJS 60 | // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) 61 | browsers: ['PhantomJS'], 62 | 63 | 64 | // If browser does not capture in given timeout [ms], kill it 65 | captureTimeout: 60000, 66 | 67 | 68 | // Continuous Integration mode 69 | // if true, it capture browsers, run tests and exit 70 | singleRun: false 71 | }); 72 | }; 73 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-bootstrap-show-errors", 3 | "version": "2.3.0", 4 | "description": "An Angular Directive to intelligently show form validation errors", 5 | "author": "Paul Yoder ", 6 | "license": "MIT", 7 | "homepage": "https://github.com/paulyoder/angular-bootstrap-show-errors", 8 | "main": "src/showErrors.js", 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "bower": "^1.3.9", 12 | "grunt": "0.4.1", 13 | "grunt-contrib-coffee": "~0.7.0", 14 | "grunt-contrib-uglify": "~0.2.5", 15 | "grunt-contrib-watch": "~0.5.3", 16 | "grunt-karma": "0.9.0", 17 | "matchdep": "0.3.0", 18 | "phantomjs": "~1.9.10", 19 | "karma-phantomjs-launcher": "~0.1.4", 20 | "karma-jasmine": "~0.1.5" 21 | }, 22 | "scripts": { 23 | "test": "grunt --verbose" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/showErrors.coffee: -------------------------------------------------------------------------------- 1 | showErrorsModule = angular.module('ui.bootstrap.showErrors', []) 2 | 3 | showErrorsModule.directive 'showErrors', 4 | ['$timeout', 'showErrorsConfig', '$interpolate', ($timeout, showErrorsConfig, $interpolate) -> 5 | 6 | getTrigger = (options) -> 7 | trigger = showErrorsConfig.trigger 8 | if options && options.trigger? 9 | trigger = options.trigger 10 | trigger 11 | 12 | getShowSuccess = (options) -> 13 | showSuccess = showErrorsConfig.showSuccess 14 | if options && options.showSuccess? 15 | showSuccess = options.showSuccess 16 | showSuccess 17 | 18 | linkFn = (scope, el, attrs, formCtrl) -> 19 | blurred = false 20 | options = scope.$eval attrs.showErrors 21 | showSuccess = getShowSuccess options 22 | trigger = getTrigger options 23 | 24 | inputEl = el[0].querySelector '.form-control[name]' 25 | inputNgEl = angular.element inputEl 26 | inputName = $interpolate(inputNgEl.attr('name') || '')(scope) 27 | unless inputName 28 | throw "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class" 29 | 30 | inputNgEl.bind trigger, -> 31 | blurred = true 32 | toggleClasses formCtrl[inputName].$invalid 33 | 34 | scope.$watch -> 35 | formCtrl[inputName] && formCtrl[inputName].$invalid 36 | , (invalid) -> 37 | return if !blurred 38 | toggleClasses invalid 39 | 40 | scope.$on 'show-errors-check-validity', -> 41 | toggleClasses formCtrl[inputName].$invalid 42 | 43 | scope.$on 'show-errors-reset', -> 44 | $timeout -> 45 | # want to run this after the current digest cycle 46 | el.removeClass 'has-error' 47 | el.removeClass 'has-success' 48 | blurred = false 49 | , 0, false 50 | 51 | toggleClasses = (invalid) -> 52 | el.toggleClass 'has-error', invalid 53 | if showSuccess 54 | el.toggleClass 'has-success', !invalid 55 | 56 | { 57 | restrict: 'A' 58 | require: '^form' 59 | compile: (elem, attrs) -> 60 | if attrs['showErrors'].indexOf('skipFormGroupCheck') == -1 61 | unless elem.hasClass('form-group') or elem.hasClass('input-group') 62 | throw "show-errors element does not have the 'form-group' or 'input-group' class" 63 | linkFn 64 | } 65 | ] 66 | 67 | showErrorsModule.provider 'showErrorsConfig', -> 68 | _showSuccess = false 69 | _trigger = 'blur' 70 | 71 | @showSuccess = (showSuccess) -> 72 | _showSuccess = showSuccess 73 | 74 | @trigger = (trigger) -> 75 | _trigger = trigger 76 | 77 | @$get = -> 78 | showSuccess: _showSuccess 79 | trigger: _trigger 80 | 81 | return 82 | -------------------------------------------------------------------------------- /src/showErrors.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var showErrorsModule; 3 | 4 | showErrorsModule = angular.module('ui.bootstrap.showErrors', []); 5 | 6 | showErrorsModule.directive('showErrors', [ 7 | '$timeout', 'showErrorsConfig', '$interpolate', function($timeout, showErrorsConfig, $interpolate) { 8 | var getShowSuccess, getTrigger, linkFn; 9 | getTrigger = function(options) { 10 | var trigger; 11 | trigger = showErrorsConfig.trigger; 12 | if (options && (options.trigger != null)) { 13 | trigger = options.trigger; 14 | } 15 | return trigger; 16 | }; 17 | getShowSuccess = function(options) { 18 | var showSuccess; 19 | showSuccess = showErrorsConfig.showSuccess; 20 | if (options && (options.showSuccess != null)) { 21 | showSuccess = options.showSuccess; 22 | } 23 | return showSuccess; 24 | }; 25 | linkFn = function(scope, el, attrs, formCtrl) { 26 | var blurred, inputEl, inputName, inputNgEl, options, showSuccess, toggleClasses, trigger; 27 | blurred = false; 28 | options = scope.$eval(attrs.showErrors); 29 | showSuccess = getShowSuccess(options); 30 | trigger = getTrigger(options); 31 | inputEl = el[0].querySelector('.form-control[name]'); 32 | inputNgEl = angular.element(inputEl); 33 | inputName = $interpolate(inputNgEl.attr('name') || '')(scope); 34 | if (!inputName) { 35 | throw "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class"; 36 | } 37 | inputNgEl.bind(trigger, function() { 38 | blurred = true; 39 | return toggleClasses(formCtrl[inputName].$invalid); 40 | }); 41 | scope.$watch(function() { 42 | return formCtrl[inputName] && formCtrl[inputName].$invalid; 43 | }, function(invalid) { 44 | if (!blurred) { 45 | return; 46 | } 47 | return toggleClasses(invalid); 48 | }); 49 | scope.$on('show-errors-check-validity', function() { 50 | return toggleClasses(formCtrl[inputName].$invalid); 51 | }); 52 | scope.$on('show-errors-reset', function() { 53 | return $timeout(function() { 54 | el.removeClass('has-error'); 55 | el.removeClass('has-success'); 56 | return blurred = false; 57 | }, 0, false); 58 | }); 59 | return toggleClasses = function(invalid) { 60 | el.toggleClass('has-error', invalid); 61 | if (showSuccess) { 62 | return el.toggleClass('has-success', !invalid); 63 | } 64 | }; 65 | }; 66 | return { 67 | restrict: 'A', 68 | require: '^form', 69 | compile: function(elem, attrs) { 70 | if (attrs['showErrors'].indexOf('skipFormGroupCheck') === -1) { 71 | if (!(elem.hasClass('form-group') || elem.hasClass('input-group'))) { 72 | throw "show-errors element does not have the 'form-group' or 'input-group' class"; 73 | } 74 | } 75 | return linkFn; 76 | } 77 | }; 78 | } 79 | ]); 80 | 81 | showErrorsModule.provider('showErrorsConfig', function() { 82 | var _showSuccess, _trigger; 83 | _showSuccess = false; 84 | _trigger = 'blur'; 85 | this.showSuccess = function(showSuccess) { 86 | return _showSuccess = showSuccess; 87 | }; 88 | this.trigger = function(trigger) { 89 | return _trigger = trigger; 90 | }; 91 | this.$get = function() { 92 | return { 93 | showSuccess: _showSuccess, 94 | trigger: _trigger 95 | }; 96 | }; 97 | }); 98 | 99 | }).call(this); 100 | -------------------------------------------------------------------------------- /src/showErrors.min.js: -------------------------------------------------------------------------------- 1 | /*! angular-bootstrap-show-errors (version 2.3.0) 2015-01-19 */ 2 | (function(){var a;a=angular.module("ui.bootstrap.showErrors",[]),a.directive("showErrors",["$timeout","showErrorsConfig","$interpolate",function(a,b,c){var d,e,f;return e=function(a){var c;return c=b.trigger,a&&null!=a.trigger&&(c=a.trigger),c},d=function(a){var c;return c=b.showSuccess,a&&null!=a.showSuccess&&(c=a.showSuccess),c},f=function(b,f,g,h){var i,j,k,l,m,n,o,p;if(i=!1,m=b.$eval(g.showErrors),n=d(m),p=e(m),j=f[0].querySelector(".form-control[name]"),l=angular.element(j),k=c(l.attr("name")||"")(b),!k)throw"show-errors element has no child input elements with a 'name' attribute and a 'form-control' class";return l.bind(p,function(){return i=!0,o(h[k].$invalid)}),b.$watch(function(){return h[k]&&h[k].$invalid},function(a){return i?o(a):void 0}),b.$on("show-errors-check-validity",function(){return o(h[k].$invalid)}),b.$on("show-errors-reset",function(){return a(function(){return f.removeClass("has-error"),f.removeClass("has-success"),i=!1},0,!1)}),o=function(a){return f.toggleClass("has-error",a),n?f.toggleClass("has-success",!a):void 0}},{restrict:"A",require:"^form",compile:function(a,b){if(-1===b.showErrors.indexOf("skipFormGroupCheck")&&!a.hasClass("form-group")&&!a.hasClass("input-group"))throw"show-errors element does not have the 'form-group' or 'input-group' class";return f}}}]),a.provider("showErrorsConfig",function(){var a,b;a=!1,b="blur",this.showSuccess=function(b){return a=b},this.trigger=function(a){return b=a},this.$get=function(){return{showSuccess:a,trigger:b}}})}).call(this); -------------------------------------------------------------------------------- /test/helpers.coffee: -------------------------------------------------------------------------------- 1 | beforeEach -> 2 | @addMatchers 3 | toHaveClass: (klass) -> 4 | @message = -> 5 | "Expected '#{ angular.mock.dump(@actual) }' to have class '#{ klass }'." 6 | 7 | @actual.hasClass klass 8 | -------------------------------------------------------------------------------- /test/helpers.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | beforeEach(function() { 3 | return this.addMatchers({ 4 | toHaveClass: function(klass) { 5 | this.message = function() { 6 | return "Expected '" + (angular.mock.dump(this.actual)) + "' to have class '" + klass + "'."; 7 | }; 8 | return this.actual.hasClass(klass); 9 | } 10 | }); 11 | }); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /test/showErrors.spec.coffee: -------------------------------------------------------------------------------- 1 | describe 'showErrors', -> 2 | $compile = undefined 3 | $scope = undefined 4 | $timeout = undefined 5 | validName = 'Paul' 6 | invalidName = 'Pa' 7 | 8 | beforeEach module('ui.bootstrap.showErrors') 9 | beforeEach inject((_$compile_, _$rootScope_, _$timeout_) -> 10 | $compile = _$compile_ 11 | $scope = _$rootScope_ 12 | $timeout = _$timeout_ 13 | ) 14 | 15 | compileEl = -> 16 | el = $compile( 17 | '
18 |
19 | 20 |
21 |
22 | 23 |
24 |
' 25 | )($scope) 26 | angular.element(document.body).append el 27 | $scope.$digest() 28 | el 29 | 30 | describe 'directive does not contain an input element with a form-control class and name attribute', -> 31 | it 'throws an exception', -> 32 | expect( -> 33 | $compile('
')($scope) 34 | ).toThrow "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class" 35 | 36 | it "throws an exception if the element doesn't have the form-group or input-group class", -> 37 | expect( -> 38 | $compile('
')($scope) 39 | ).toThrow "show-errors element does not have the 'form-group' or 'input-group' class" 40 | 41 | it "doesn't throw an exception if the element has the input-group class", -> 42 | expect( -> 43 | $compile('
')($scope) 44 | ).not.toThrow() 45 | 46 | it "doesn't throw an exception if the element doesn't have the form-group class but uses the skipFormGroupCheck option", -> 47 | expect( -> 48 | $compile('
')($scope) 49 | ).not.toThrow() 50 | 51 | it "throws an exception if the element isn't in a form tag", -> 52 | expect( -> 53 | $compile('
')($scope) 54 | ).toThrow() 55 | 56 | describe '$pristine && $invalid', -> 57 | it 'has-error is absent', -> 58 | el = compileEl() 59 | expectFormGroupHasErrorClass(el).toBe false 60 | 61 | describe '$dirty && $invalid && blurred', -> 62 | it 'has-error is present', -> 63 | el = compileEl() 64 | $scope.userForm.firstName.$setViewValue invalidName 65 | angular.element(firstNameEl(el)).triggerHandler 'blur' 66 | expectFormGroupHasErrorClass(el).toBe true 67 | 68 | describe '$dirty && $invalid && not blurred', -> 69 | it 'has-error is absent', -> 70 | el = compileEl() 71 | $scope.userForm.firstName.$setViewValue invalidName 72 | angular.element(firstNameEl(el)).triggerHandler 'keydown' 73 | expectFormGroupHasErrorClass(el).toBe false 74 | 75 | describe '$valid && blurred', -> 76 | it 'has-error is absent', -> 77 | el = compileEl() 78 | $scope.userForm.firstName.$setViewValue validName 79 | angular.element(firstNameEl(el)).triggerHandler 'blur' 80 | expectFormGroupHasErrorClass(el).toBe false 81 | 82 | describe '$valid && blurred then becomes $invalid before blurred', -> 83 | it 'has-error is present', -> 84 | el = compileEl() 85 | $scope.userForm.firstName.$setViewValue validName 86 | angular.element(firstNameEl(el)).triggerHandler 'blur' 87 | $scope.$apply -> 88 | $scope.userForm.firstName.$setViewValue invalidName 89 | expectFormGroupHasErrorClass(el).toBe true 90 | 91 | describe '$valid && blurred then becomes $valid before blurred', -> 92 | it 'has-error is absent', -> 93 | el = compileEl() 94 | $scope.userForm.firstName.$setViewValue validName 95 | angular.element(firstNameEl(el)).triggerHandler 'blur' 96 | $scope.$apply -> 97 | $scope.userForm.firstName.$setViewValue invalidName 98 | $scope.$apply -> 99 | $scope.userForm.firstName.$setViewValue validName 100 | expectFormGroupHasErrorClass(el).toBe false 101 | 102 | describe '$valid && blurred then becomes $invalid after blurred', -> 103 | it 'has-error is present', -> 104 | el = compileEl() 105 | $scope.userForm.firstName.$setViewValue validName 106 | angular.element(firstNameEl(el)).triggerHandler 'blur' 107 | $scope.userForm.firstName.$setViewValue invalidName 108 | angular.element(firstNameEl(el)).triggerHandler 'blur' 109 | expectFormGroupHasErrorClass(el).toBe true 110 | 111 | describe '$valid && blurred then $invalid after blurred then $valid after blurred', -> 112 | it 'has-error is absent', -> 113 | el = compileEl() 114 | $scope.userForm.firstName.$setViewValue validName 115 | angular.element(firstNameEl(el)).triggerHandler 'blur' 116 | $scope.userForm.firstName.$setViewValue invalidName 117 | angular.element(firstNameEl(el)).triggerHandler 'blur' 118 | $scope.userForm.firstName.$setViewValue validName 119 | angular.element(firstNameEl(el)).triggerHandler 'blur' 120 | expectFormGroupHasErrorClass(el).toBe false 121 | 122 | describe '$valid && other input is $invalid && blurred', -> 123 | it 'has-error is absent', -> 124 | el = compileEl() 125 | $scope.userForm.firstName.$setViewValue validName 126 | $scope.userForm.lastName.$setViewValue invalidName 127 | angular.element(firstNameEl(el)).triggerHandler 'blur' 128 | expectFormGroupHasErrorClass(el).toBe false 129 | 130 | describe '$invalid && showErrorsCheckValidity is set before blurred', -> 131 | it 'has-error is present', -> 132 | el = compileEl() 133 | $scope.userForm.firstName.$setViewValue invalidName 134 | $scope.$broadcast 'show-errors-check-validity' 135 | expectFormGroupHasErrorClass(el).toBe true 136 | 137 | describe 'showErrorsCheckValidity is called twice', -> 138 | it 'correctly applies the has-error class', -> 139 | el = compileEl() 140 | $scope.userForm.firstName.$setViewValue invalidName 141 | $scope.$broadcast 'show-errors-check-validity' 142 | $scope.userForm.firstName.$setViewValue validName 143 | angular.element(firstNameEl(el)).triggerHandler 'blur' 144 | $scope.userForm.firstName.$setViewValue invalidName 145 | $scope.$apply -> 146 | $scope.showErrorsCheckValidity = true 147 | expectFormGroupHasErrorClass(el).toBe true 148 | 149 | describe 'showErrorsReset', -> 150 | it 'removes has-error', -> 151 | el = compileEl() 152 | $scope.userForm.firstName.$setViewValue invalidName 153 | angular.element(firstNameEl(el)).triggerHandler 'blur' 154 | $scope.$broadcast 'show-errors-reset' 155 | $timeout.flush() 156 | expectFormGroupHasErrorClass(el).toBe false 157 | 158 | describe 'showErrorsReset then invalid without blurred', -> 159 | it 'has-error is absent', -> 160 | el = compileEl() 161 | $scope.userForm.firstName.$setViewValue validName 162 | angular.element(firstNameEl(el)).triggerHandler 'blur' 163 | $scope.$broadcast 'show-errors-reset' 164 | $timeout.flush() 165 | $scope.$apply -> 166 | $scope.userForm.firstName.$setViewValue invalidName 167 | expectFormGroupHasErrorClass(el).toBe false 168 | 169 | describe 'call showErrorsReset multiple times', -> 170 | it 'removes has-error', -> 171 | el = compileEl() 172 | $scope.userForm.firstName.$setViewValue invalidName 173 | angular.element(firstNameEl(el)).triggerHandler 'blur' 174 | $scope.$broadcast 'show-errors-reset' 175 | $timeout.flush() 176 | angular.element(firstNameEl(el)).triggerHandler 'blur' 177 | $scope.$broadcast 'show-errors-reset' 178 | $timeout.flush() 179 | expectFormGroupHasErrorClass(el).toBe false 180 | 181 | describe '{showSuccess: true} option', -> 182 | describe '$pristine && $valid', -> 183 | it 'has-success is absent', -> 184 | el = compileEl() 185 | expectLastNameFormGroupHasSuccessClass(el).toBe false 186 | 187 | describe '$dirty && $valid && blurred', -> 188 | it 'has-success is present', -> 189 | el = compileEl() 190 | $scope.userForm.lastName.$setViewValue validName 191 | angular.element(lastNameEl(el)).triggerHandler 'blur' 192 | $scope.$digest() 193 | expectLastNameFormGroupHasSuccessClass(el).toBe true 194 | 195 | describe '$dirty && $invalid && blurred', -> 196 | it 'has-success is present', -> 197 | el = compileEl() 198 | $scope.userForm.lastName.$setViewValue invalidName 199 | angular.element(lastNameEl(el)).triggerHandler 'blur' 200 | $scope.$digest() 201 | expectLastNameFormGroupHasSuccessClass(el).toBe false 202 | 203 | describe '$invalid && blurred then becomes $valid before blurred', -> 204 | it 'has-success is present', -> 205 | el = compileEl() 206 | $scope.userForm.lastName.$setViewValue invalidName 207 | angular.element(lastNameEl(el)).triggerHandler 'blur' 208 | $scope.$apply -> 209 | $scope.userForm.lastName.$setViewValue invalidName 210 | $scope.$apply -> 211 | $scope.userForm.lastName.$setViewValue validName 212 | expectLastNameFormGroupHasSuccessClass(el).toBe true 213 | 214 | describe '$valid && showErrorsCheckValidity is set before blurred', -> 215 | it 'has-success is present', -> 216 | el = compileEl() 217 | $scope.userForm.lastName.$setViewValue validName 218 | $scope.$broadcast 'show-errors-check-validity' 219 | expectLastNameFormGroupHasSuccessClass(el).toBe true 220 | 221 | describe 'showErrorsReset', -> 222 | it 'removes has-success', -> 223 | el = compileEl() 224 | $scope.userForm.lastName.$setViewValue validName 225 | angular.element(lastNameEl(el)).triggerHandler 'blur' 226 | $scope.$broadcast 'show-errors-reset' 227 | $timeout.flush() 228 | expectLastNameFormGroupHasSuccessClass(el).toBe false 229 | 230 | describe 'showErrorsConfig', -> 231 | $compile = undefined 232 | $scope = undefined 233 | $timeout = undefined 234 | validName = 'Paul' 235 | invalidName = 'Pa' 236 | 237 | beforeEach -> 238 | testModule = angular.module 'testModule', [] 239 | testModule.config (showErrorsConfigProvider) -> 240 | showErrorsConfigProvider.showSuccess true 241 | showErrorsConfigProvider.trigger 'keypress' 242 | 243 | module 'ui.bootstrap.showErrors', 'testModule' 244 | 245 | inject((_$compile_, _$rootScope_, _$timeout_) -> 246 | $compile = _$compile_ 247 | $scope = _$rootScope_ 248 | $timeout = _$timeout_ 249 | ) 250 | 251 | compileEl = -> 252 | el = $compile( 253 | '
254 |
255 | 256 |
257 |
258 | 259 |
260 |
' 261 | )($scope) 262 | angular.element(document.body).append el 263 | $scope.$digest() 264 | el 265 | 266 | describe 'when showErrorsConfig.showSuccess is true', -> 267 | describe 'and no options given', -> 268 | it 'show-success class is applied', -> 269 | el = compileEl() 270 | $scope.userForm.lastName.$setViewValue validName 271 | angular.element(lastNameEl(el)).triggerHandler 'keypress' 272 | $scope.$digest() 273 | expectLastNameFormGroupHasSuccessClass(el).toBe true 274 | 275 | describe 'when showErrorsConfig.showSuccess is true', -> 276 | describe 'but options.showSuccess is false', -> 277 | it 'show-success class is not applied', -> 278 | el = compileEl() 279 | $scope.userForm.firstName.$setViewValue validName 280 | angular.element(firstNameEl(el)).triggerHandler 'blur' 281 | $scope.$digest() 282 | expectFirstNameFormGroupHasSuccessClass(el).toBe false 283 | 284 | describe 'when showErrorsConfig.trigger is "keypress"', -> 285 | describe 'and no options given', -> 286 | it 'validates the value on the first keypress', -> 287 | el = compileEl() 288 | $scope.userForm.lastName.$setViewValue invalidName 289 | angular.element(lastNameEl(el)).triggerHandler 'keypress' 290 | $scope.$digest() 291 | expectLastNameFormGroupHasErrorClass(el).toBe true 292 | 293 | describe 'but options.trigger is "blur"', -> 294 | it 'does not validate the value on keypress', -> 295 | el = compileEl() 296 | $scope.userForm.firstName.$setViewValue invalidName 297 | angular.element(firstNameEl(el)).triggerHandler 'keypress' 298 | $scope.$digest() 299 | expectFirstNameFormGroupHasErrorClass(el).toBe false 300 | 301 | find = (el, selector) -> 302 | el[0].querySelector selector 303 | 304 | firstNameEl = (el) -> 305 | find el, '[name=firstName]' 306 | 307 | lastNameEl = (el) -> 308 | find el, '[name=lastName]' 309 | 310 | expectFormGroupHasErrorClass = (el) -> 311 | formGroup = el[0].querySelector '[id=first-name-group]' 312 | expect angular.element(formGroup).hasClass('has-error') 313 | 314 | expectFirstNameFormGroupHasSuccessClass = (el) -> 315 | formGroup = el[0].querySelector '[id=first-name-group]' 316 | expect angular.element(formGroup).hasClass('has-success') 317 | 318 | expectLastNameFormGroupHasSuccessClass = (el) -> 319 | formGroup = el[0].querySelector '[id=last-name-group]' 320 | expect angular.element(formGroup).hasClass('has-success') 321 | 322 | expectFirstNameFormGroupHasErrorClass = (el) -> 323 | formGroup = el[0].querySelector '[id=first-name-group]' 324 | expect angular.element(formGroup).hasClass('has-error') 325 | 326 | expectLastNameFormGroupHasErrorClass = (el) -> 327 | formGroup = el[0].querySelector '[id=last-name-group]' 328 | expect angular.element(formGroup).hasClass('has-error') 329 | -------------------------------------------------------------------------------- /test/showErrors.spec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var expectFirstNameFormGroupHasErrorClass, expectFirstNameFormGroupHasSuccessClass, expectFormGroupHasErrorClass, expectLastNameFormGroupHasErrorClass, expectLastNameFormGroupHasSuccessClass, find, firstNameEl, lastNameEl; 3 | 4 | describe('showErrors', function() { 5 | var $compile, $scope, $timeout, compileEl, invalidName, validName; 6 | $compile = void 0; 7 | $scope = void 0; 8 | $timeout = void 0; 9 | validName = 'Paul'; 10 | invalidName = 'Pa'; 11 | beforeEach(module('ui.bootstrap.showErrors')); 12 | beforeEach(inject(function(_$compile_, _$rootScope_, _$timeout_) { 13 | $compile = _$compile_; 14 | $scope = _$rootScope_; 15 | return $timeout = _$timeout_; 16 | })); 17 | compileEl = function() { 18 | var el; 19 | el = $compile('
\ 20 |
\ 21 | \ 22 |
\ 23 |
\ 24 | \ 25 |
\ 26 |
')($scope); 27 | angular.element(document.body).append(el); 28 | $scope.$digest(); 29 | return el; 30 | }; 31 | describe('directive does not contain an input element with a form-control class and name attribute', function() { 32 | return it('throws an exception', function() { 33 | return expect(function() { 34 | return $compile('
')($scope); 35 | }).toThrow("show-errors element has no child input elements with a 'name' attribute and a 'form-control' class"); 36 | }); 37 | }); 38 | it("throws an exception if the element doesn't have the form-group or input-group class", function() { 39 | return expect(function() { 40 | return $compile('
')($scope); 41 | }).toThrow("show-errors element does not have the 'form-group' or 'input-group' class"); 42 | }); 43 | it("doesn't throw an exception if the element has the input-group class", function() { 44 | return expect(function() { 45 | return $compile('
')($scope); 46 | }).not.toThrow(); 47 | }); 48 | it("doesn't throw an exception if the element doesn't have the form-group class but uses the skipFormGroupCheck option", function() { 49 | return expect(function() { 50 | return $compile('
')($scope); 51 | }).not.toThrow(); 52 | }); 53 | it("throws an exception if the element isn't in a form tag", function() { 54 | return expect(function() { 55 | return $compile('
')($scope); 56 | }).toThrow(); 57 | }); 58 | describe('$pristine && $invalid', function() { 59 | return it('has-error is absent', function() { 60 | var el; 61 | el = compileEl(); 62 | return expectFormGroupHasErrorClass(el).toBe(false); 63 | }); 64 | }); 65 | describe('$dirty && $invalid && blurred', function() { 66 | return it('has-error is present', function() { 67 | var el; 68 | el = compileEl(); 69 | $scope.userForm.firstName.$setViewValue(invalidName); 70 | angular.element(firstNameEl(el)).triggerHandler('blur'); 71 | return expectFormGroupHasErrorClass(el).toBe(true); 72 | }); 73 | }); 74 | describe('$dirty && $invalid && not blurred', function() { 75 | return it('has-error is absent', function() { 76 | var el; 77 | el = compileEl(); 78 | $scope.userForm.firstName.$setViewValue(invalidName); 79 | angular.element(firstNameEl(el)).triggerHandler('keydown'); 80 | return expectFormGroupHasErrorClass(el).toBe(false); 81 | }); 82 | }); 83 | describe('$valid && blurred', function() { 84 | return it('has-error is absent', function() { 85 | var el; 86 | el = compileEl(); 87 | $scope.userForm.firstName.$setViewValue(validName); 88 | angular.element(firstNameEl(el)).triggerHandler('blur'); 89 | return expectFormGroupHasErrorClass(el).toBe(false); 90 | }); 91 | }); 92 | describe('$valid && blurred then becomes $invalid before blurred', function() { 93 | return it('has-error is present', function() { 94 | var el; 95 | el = compileEl(); 96 | $scope.userForm.firstName.$setViewValue(validName); 97 | angular.element(firstNameEl(el)).triggerHandler('blur'); 98 | $scope.$apply(function() { 99 | return $scope.userForm.firstName.$setViewValue(invalidName); 100 | }); 101 | return expectFormGroupHasErrorClass(el).toBe(true); 102 | }); 103 | }); 104 | describe('$valid && blurred then becomes $valid before blurred', function() { 105 | return it('has-error is absent', function() { 106 | var el; 107 | el = compileEl(); 108 | $scope.userForm.firstName.$setViewValue(validName); 109 | angular.element(firstNameEl(el)).triggerHandler('blur'); 110 | $scope.$apply(function() { 111 | return $scope.userForm.firstName.$setViewValue(invalidName); 112 | }); 113 | $scope.$apply(function() { 114 | return $scope.userForm.firstName.$setViewValue(validName); 115 | }); 116 | return expectFormGroupHasErrorClass(el).toBe(false); 117 | }); 118 | }); 119 | describe('$valid && blurred then becomes $invalid after blurred', function() { 120 | return it('has-error is present', function() { 121 | var el; 122 | el = compileEl(); 123 | $scope.userForm.firstName.$setViewValue(validName); 124 | angular.element(firstNameEl(el)).triggerHandler('blur'); 125 | $scope.userForm.firstName.$setViewValue(invalidName); 126 | angular.element(firstNameEl(el)).triggerHandler('blur'); 127 | return expectFormGroupHasErrorClass(el).toBe(true); 128 | }); 129 | }); 130 | describe('$valid && blurred then $invalid after blurred then $valid after blurred', function() { 131 | return it('has-error is absent', function() { 132 | var el; 133 | el = compileEl(); 134 | $scope.userForm.firstName.$setViewValue(validName); 135 | angular.element(firstNameEl(el)).triggerHandler('blur'); 136 | $scope.userForm.firstName.$setViewValue(invalidName); 137 | angular.element(firstNameEl(el)).triggerHandler('blur'); 138 | $scope.userForm.firstName.$setViewValue(validName); 139 | angular.element(firstNameEl(el)).triggerHandler('blur'); 140 | return expectFormGroupHasErrorClass(el).toBe(false); 141 | }); 142 | }); 143 | describe('$valid && other input is $invalid && blurred', function() { 144 | return it('has-error is absent', function() { 145 | var el; 146 | el = compileEl(); 147 | $scope.userForm.firstName.$setViewValue(validName); 148 | $scope.userForm.lastName.$setViewValue(invalidName); 149 | angular.element(firstNameEl(el)).triggerHandler('blur'); 150 | return expectFormGroupHasErrorClass(el).toBe(false); 151 | }); 152 | }); 153 | describe('$invalid && showErrorsCheckValidity is set before blurred', function() { 154 | return it('has-error is present', function() { 155 | var el; 156 | el = compileEl(); 157 | $scope.userForm.firstName.$setViewValue(invalidName); 158 | $scope.$broadcast('show-errors-check-validity'); 159 | return expectFormGroupHasErrorClass(el).toBe(true); 160 | }); 161 | }); 162 | describe('showErrorsCheckValidity is called twice', function() { 163 | return it('correctly applies the has-error class', function() { 164 | var el; 165 | el = compileEl(); 166 | $scope.userForm.firstName.$setViewValue(invalidName); 167 | $scope.$broadcast('show-errors-check-validity'); 168 | $scope.userForm.firstName.$setViewValue(validName); 169 | angular.element(firstNameEl(el)).triggerHandler('blur'); 170 | $scope.userForm.firstName.$setViewValue(invalidName); 171 | $scope.$apply(function() { 172 | return $scope.showErrorsCheckValidity = true; 173 | }); 174 | return expectFormGroupHasErrorClass(el).toBe(true); 175 | }); 176 | }); 177 | describe('showErrorsReset', function() { 178 | return it('removes has-error', function() { 179 | var el; 180 | el = compileEl(); 181 | $scope.userForm.firstName.$setViewValue(invalidName); 182 | angular.element(firstNameEl(el)).triggerHandler('blur'); 183 | $scope.$broadcast('show-errors-reset'); 184 | $timeout.flush(); 185 | return expectFormGroupHasErrorClass(el).toBe(false); 186 | }); 187 | }); 188 | describe('showErrorsReset then invalid without blurred', function() { 189 | return it('has-error is absent', function() { 190 | var el; 191 | el = compileEl(); 192 | $scope.userForm.firstName.$setViewValue(validName); 193 | angular.element(firstNameEl(el)).triggerHandler('blur'); 194 | $scope.$broadcast('show-errors-reset'); 195 | $timeout.flush(); 196 | $scope.$apply(function() { 197 | return $scope.userForm.firstName.$setViewValue(invalidName); 198 | }); 199 | return expectFormGroupHasErrorClass(el).toBe(false); 200 | }); 201 | }); 202 | describe('call showErrorsReset multiple times', function() { 203 | return it('removes has-error', function() { 204 | var el; 205 | el = compileEl(); 206 | $scope.userForm.firstName.$setViewValue(invalidName); 207 | angular.element(firstNameEl(el)).triggerHandler('blur'); 208 | $scope.$broadcast('show-errors-reset'); 209 | $timeout.flush(); 210 | angular.element(firstNameEl(el)).triggerHandler('blur'); 211 | $scope.$broadcast('show-errors-reset'); 212 | $timeout.flush(); 213 | return expectFormGroupHasErrorClass(el).toBe(false); 214 | }); 215 | }); 216 | return describe('{showSuccess: true} option', function() { 217 | describe('$pristine && $valid', function() { 218 | return it('has-success is absent', function() { 219 | var el; 220 | el = compileEl(); 221 | return expectLastNameFormGroupHasSuccessClass(el).toBe(false); 222 | }); 223 | }); 224 | describe('$dirty && $valid && blurred', function() { 225 | return it('has-success is present', function() { 226 | var el; 227 | el = compileEl(); 228 | $scope.userForm.lastName.$setViewValue(validName); 229 | angular.element(lastNameEl(el)).triggerHandler('blur'); 230 | $scope.$digest(); 231 | return expectLastNameFormGroupHasSuccessClass(el).toBe(true); 232 | }); 233 | }); 234 | describe('$dirty && $invalid && blurred', function() { 235 | return it('has-success is present', function() { 236 | var el; 237 | el = compileEl(); 238 | $scope.userForm.lastName.$setViewValue(invalidName); 239 | angular.element(lastNameEl(el)).triggerHandler('blur'); 240 | $scope.$digest(); 241 | return expectLastNameFormGroupHasSuccessClass(el).toBe(false); 242 | }); 243 | }); 244 | describe('$invalid && blurred then becomes $valid before blurred', function() { 245 | return it('has-success is present', function() { 246 | var el; 247 | el = compileEl(); 248 | $scope.userForm.lastName.$setViewValue(invalidName); 249 | angular.element(lastNameEl(el)).triggerHandler('blur'); 250 | $scope.$apply(function() { 251 | return $scope.userForm.lastName.$setViewValue(invalidName); 252 | }); 253 | $scope.$apply(function() { 254 | return $scope.userForm.lastName.$setViewValue(validName); 255 | }); 256 | return expectLastNameFormGroupHasSuccessClass(el).toBe(true); 257 | }); 258 | }); 259 | describe('$valid && showErrorsCheckValidity is set before blurred', function() { 260 | return it('has-success is present', function() { 261 | var el; 262 | el = compileEl(); 263 | $scope.userForm.lastName.$setViewValue(validName); 264 | $scope.$broadcast('show-errors-check-validity'); 265 | return expectLastNameFormGroupHasSuccessClass(el).toBe(true); 266 | }); 267 | }); 268 | return describe('showErrorsReset', function() { 269 | return it('removes has-success', function() { 270 | var el; 271 | el = compileEl(); 272 | $scope.userForm.lastName.$setViewValue(validName); 273 | angular.element(lastNameEl(el)).triggerHandler('blur'); 274 | $scope.$broadcast('show-errors-reset'); 275 | $timeout.flush(); 276 | return expectLastNameFormGroupHasSuccessClass(el).toBe(false); 277 | }); 278 | }); 279 | }); 280 | }); 281 | 282 | describe('showErrorsConfig', function() { 283 | var $compile, $scope, $timeout, compileEl, invalidName, validName; 284 | $compile = void 0; 285 | $scope = void 0; 286 | $timeout = void 0; 287 | validName = 'Paul'; 288 | invalidName = 'Pa'; 289 | beforeEach(function() { 290 | var testModule; 291 | testModule = angular.module('testModule', []); 292 | testModule.config(function(showErrorsConfigProvider) { 293 | showErrorsConfigProvider.showSuccess(true); 294 | return showErrorsConfigProvider.trigger('keypress'); 295 | }); 296 | module('ui.bootstrap.showErrors', 'testModule'); 297 | return inject(function(_$compile_, _$rootScope_, _$timeout_) { 298 | $compile = _$compile_; 299 | $scope = _$rootScope_; 300 | return $timeout = _$timeout_; 301 | }); 302 | }); 303 | compileEl = function() { 304 | var el; 305 | el = $compile('
\ 306 |
\ 307 | \ 308 |
\ 309 |
\ 310 | \ 311 |
\ 312 |
')($scope); 313 | angular.element(document.body).append(el); 314 | $scope.$digest(); 315 | return el; 316 | }; 317 | describe('when showErrorsConfig.showSuccess is true', function() { 318 | return describe('and no options given', function() { 319 | return it('show-success class is applied', function() { 320 | var el; 321 | el = compileEl(); 322 | $scope.userForm.lastName.$setViewValue(validName); 323 | angular.element(lastNameEl(el)).triggerHandler('keypress'); 324 | $scope.$digest(); 325 | return expectLastNameFormGroupHasSuccessClass(el).toBe(true); 326 | }); 327 | }); 328 | }); 329 | describe('when showErrorsConfig.showSuccess is true', function() { 330 | return describe('but options.showSuccess is false', function() { 331 | return it('show-success class is not applied', function() { 332 | var el; 333 | el = compileEl(); 334 | $scope.userForm.firstName.$setViewValue(validName); 335 | angular.element(firstNameEl(el)).triggerHandler('blur'); 336 | $scope.$digest(); 337 | return expectFirstNameFormGroupHasSuccessClass(el).toBe(false); 338 | }); 339 | }); 340 | }); 341 | return describe('when showErrorsConfig.trigger is "keypress"', function() { 342 | describe('and no options given', function() { 343 | return it('validates the value on the first keypress', function() { 344 | var el; 345 | el = compileEl(); 346 | $scope.userForm.lastName.$setViewValue(invalidName); 347 | angular.element(lastNameEl(el)).triggerHandler('keypress'); 348 | $scope.$digest(); 349 | return expectLastNameFormGroupHasErrorClass(el).toBe(true); 350 | }); 351 | }); 352 | return describe('but options.trigger is "blur"', function() { 353 | return it('does not validate the value on keypress', function() { 354 | var el; 355 | el = compileEl(); 356 | $scope.userForm.firstName.$setViewValue(invalidName); 357 | angular.element(firstNameEl(el)).triggerHandler('keypress'); 358 | $scope.$digest(); 359 | return expectFirstNameFormGroupHasErrorClass(el).toBe(false); 360 | }); 361 | }); 362 | }); 363 | }); 364 | 365 | find = function(el, selector) { 366 | return el[0].querySelector(selector); 367 | }; 368 | 369 | firstNameEl = function(el) { 370 | return find(el, '[name=firstName]'); 371 | }; 372 | 373 | lastNameEl = function(el) { 374 | return find(el, '[name=lastName]'); 375 | }; 376 | 377 | expectFormGroupHasErrorClass = function(el) { 378 | var formGroup; 379 | formGroup = el[0].querySelector('[id=first-name-group]'); 380 | return expect(angular.element(formGroup).hasClass('has-error')); 381 | }; 382 | 383 | expectFirstNameFormGroupHasSuccessClass = function(el) { 384 | var formGroup; 385 | formGroup = el[0].querySelector('[id=first-name-group]'); 386 | return expect(angular.element(formGroup).hasClass('has-success')); 387 | }; 388 | 389 | expectLastNameFormGroupHasSuccessClass = function(el) { 390 | var formGroup; 391 | formGroup = el[0].querySelector('[id=last-name-group]'); 392 | return expect(angular.element(formGroup).hasClass('has-success')); 393 | }; 394 | 395 | expectFirstNameFormGroupHasErrorClass = function(el) { 396 | var formGroup; 397 | formGroup = el[0].querySelector('[id=first-name-group]'); 398 | return expect(angular.element(formGroup).hasClass('has-error')); 399 | }; 400 | 401 | expectLastNameFormGroupHasErrorClass = function(el) { 402 | var formGroup; 403 | formGroup = el[0].querySelector('[id=last-name-group]'); 404 | return expect(angular.element(formGroup).hasClass('has-error')); 405 | }; 406 | 407 | }).call(this); 408 | --------------------------------------------------------------------------------