Skip to content

Commit f0b4dfe

Browse files
committed
added showSuccess option
1 parent db5c3d7 commit f0b4dfe

9 files changed

Lines changed: 399 additions & 47 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
### 1.1.0
2+
3+
* Enhancements
4+
* Added `showSuccess` option
5+
6+
* Bug Fixes
7+
* Does not throw an undefined error when the form is dynamically created. Thanks @murphyalexandre
8+
19
### 1.0.4
210

311
* Bug Fixes

README.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ Copy the `src/showErrors.js` or `src/showErrors.min.js` file into your project.
1818
Quick Start
1919
---
2020
1. Include the `ui.bootstrap.showErrors` module in your Angular app
21-
2. Add the `show-errors` attribute on the form div element that contains the `form-group` class
21+
```javascript
22+
angular.module('yourApp', ['ui.bootstrap.showErrors']);
23+
```
2224

25+
2. Add the `show-errors` attribute on the div element that contains the `form-group` class
2326
```html
2427
<form name="userForm">
2528
<div class="form-group" show-errors>
@@ -76,6 +79,32 @@ $scope.reset = function() {
7679
$scope.$broadcast('show-errors-reset');
7780
}
7881
```
82+
83+
Show Valid Entries
84+
---
85+
It's also possible to let the user know when they have entered valid values by applying the 'show-success' class that Bootstrap provides.
86+
You can either apply this globally or on an element by element basis.
87+
88+
##### Globally
89+
The following example shows how to show valid values on every input that uses the showErrors directive.
90+
91+
```javascript
92+
app = angular.module('yourApp', ['ui.bootstrap.showErrors']);
93+
app.config(['showErrorsConfigProvider', function(showErrorsConfigProvider) {
94+
showErrorsConfigProvider.showSuccess(true);
95+
});
96+
```
97+
98+
##### By Input
99+
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.
100+
101+
```html
102+
<form name="userForm">
103+
<div class="form-group" show-errors="{ showSuccess: true }">
104+
<input type="text" name="firstName" ng-model="firstName" ng-required />
105+
</div>
106+
</form>
107+
```
79108

80109
## Development
81110

bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-bootstrap-show-errors",
3-
"version": "1.0.4",
3+
"version": "1.1.0",
44
"authors": [
55
"Paul Yoder <paulyoder@gmail.com>"
66
],

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "angular-bootstrap-show-errors",
3-
"version": "1.0.2",
3+
"version": "1.1.0",
44
"description": "An Angular Directive to intelligently show form validation errors",
55
"author": "https://github.com/paulyoder/angular-bootstrap-show-errors/graphs/contributors",
66
"license": "MIT",

src/showErrors.coffee

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1-
angular.module('ui.bootstrap.showErrors', [])
2-
.directive 'showErrors', ['$timeout', ($timeout) ->
1+
showErrorsModule = angular.module('ui.bootstrap.showErrors', [])
2+
3+
showErrorsModule.directive 'showErrors',
4+
['$timeout', 'showErrorsConfig', ($timeout, showErrorsConfig) ->
5+
6+
getShowSuccess = (options) ->
7+
showSuccess = showErrorsConfig.showSuccess
8+
if options && options.showSuccess?
9+
showSuccess = options.showSuccess
10+
showSuccess
311

412
linkFn = (scope, el, attrs, formCtrl) ->
513
blurred = false
14+
options = scope.$eval attrs.showErrors
15+
showSuccess = getShowSuccess options
16+
617
inputEl = el[0].querySelector("[name]")
718
inputNgEl = angular.element(inputEl)
819
inputName = inputNgEl.attr('name')
@@ -11,24 +22,30 @@ angular.module('ui.bootstrap.showErrors', [])
1122

1223
inputNgEl.bind 'blur', ->
1324
blurred = true
14-
el.toggleClass 'has-error', formCtrl[inputName].$invalid
25+
toggleClasses formCtrl[inputName].$invalid
1526

1627
scope.$watch ->
1728
formCtrl[inputName] && formCtrl[inputName].$invalid
1829
, (invalid) ->
19-
return if !blurred && invalid
20-
el.toggleClass 'has-error', invalid
30+
return if !blurred
31+
toggleClasses invalid
2132

2233
scope.$on 'show-errors-check-validity', ->
23-
el.toggleClass 'has-error', formCtrl[inputName].$invalid
34+
toggleClasses formCtrl[inputName].$invalid
2435

2536
scope.$on 'show-errors-reset', ->
2637
$timeout ->
2738
# want to run this after the current digest cycle
2839
el.removeClass 'has-error'
40+
el.removeClass 'has-success'
2941
blurred = false
3042
, 0, false
3143

44+
toggleClasses = (invalid) ->
45+
el.toggleClass 'has-error', invalid
46+
if showSuccess
47+
el.toggleClass 'has-success', !invalid
48+
3249
{
3350
restrict: 'A'
3451
require: '^form'
@@ -38,3 +55,14 @@ angular.module('ui.bootstrap.showErrors', [])
3855
linkFn
3956
}
4057
]
58+
59+
showErrorsModule.provider 'showErrorsConfig', ->
60+
_showSuccess = false
61+
62+
@showSuccess = (showSuccess) ->
63+
_showSuccess = showSuccess
64+
65+
@$get = ->
66+
showSuccess: _showSuccess
67+
68+
return

src/showErrors.js

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
11
(function () {
2-
angular.module('ui.bootstrap.showErrors', []).directive('showErrors', [
2+
var showErrorsModule;
3+
showErrorsModule = angular.module('ui.bootstrap.showErrors', []);
4+
showErrorsModule.directive('showErrors', [
35
'$timeout',
4-
function ($timeout) {
5-
var linkFn;
6+
'showErrorsConfig',
7+
function ($timeout, showErrorsConfig) {
8+
var getShowSuccess, linkFn;
9+
getShowSuccess = function (options) {
10+
var showSuccess;
11+
showSuccess = showErrorsConfig.showSuccess;
12+
if (options && options.showSuccess != null) {
13+
showSuccess = options.showSuccess;
14+
}
15+
return showSuccess;
16+
};
617
linkFn = function (scope, el, attrs, formCtrl) {
7-
var blurred, inputEl, inputName, inputNgEl;
18+
var blurred, inputEl, inputName, inputNgEl, options, showSuccess, toggleClasses;
819
blurred = false;
20+
options = scope.$eval(attrs.showErrors);
21+
showSuccess = getShowSuccess(options);
922
inputEl = el[0].querySelector('[name]');
1023
inputNgEl = angular.element(inputEl);
1124
inputName = inputNgEl.attr('name');
@@ -14,25 +27,32 @@
1427
}
1528
inputNgEl.bind('blur', function () {
1629
blurred = true;
17-
return el.toggleClass('has-error', formCtrl[inputName].$invalid);
30+
return toggleClasses(formCtrl[inputName].$invalid);
1831
});
1932
scope.$watch(function () {
2033
return formCtrl[inputName] && formCtrl[inputName].$invalid;
2134
}, function (invalid) {
22-
if (!blurred && invalid) {
35+
if (!blurred) {
2336
return;
2437
}
25-
return el.toggleClass('has-error', invalid);
38+
return toggleClasses(invalid);
2639
});
2740
scope.$on('show-errors-check-validity', function () {
28-
return el.toggleClass('has-error', formCtrl[inputName].$invalid);
41+
return toggleClasses(formCtrl[inputName].$invalid);
2942
});
30-
return scope.$on('show-errors-reset', function () {
43+
scope.$on('show-errors-reset', function () {
3144
return $timeout(function () {
3245
el.removeClass('has-error');
46+
el.removeClass('has-success');
3347
return blurred = false;
3448
}, 0, false);
3549
});
50+
return toggleClasses = function (invalid) {
51+
el.toggleClass('has-error', invalid);
52+
if (showSuccess) {
53+
return el.toggleClass('has-success', !invalid);
54+
}
55+
};
3656
};
3757
return {
3858
restrict: 'A',
@@ -46,4 +66,14 @@
4666
};
4767
}
4868
]);
69+
showErrorsModule.provider('showErrorsConfig', function () {
70+
var _showSuccess;
71+
_showSuccess = false;
72+
this.showSuccess = function (showSuccess) {
73+
return _showSuccess = showSuccess;
74+
};
75+
this.$get = function () {
76+
return { showSuccess: _showSuccess };
77+
};
78+
});
4979
}.call(this));

src/showErrors.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/showErrors.spec.coffee

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe 'showErrors', ->
1818
<div id="first-name-group" class="form-group" show-errors>
1919
<input type="text" name="firstName" ng-model="firstName" ng-minlength="3" />
2020
</div>
21-
<div class="form-group" show-errors>
21+
<div id="last-name-group" class="form-group" show-errors="{ showSuccess: true }">
2222
<input type="text" name="lastName" ng-model="lastName" ng-minlength="3" />
2323
</div>
2424
</form>'
@@ -27,16 +27,6 @@ describe 'showErrors', ->
2727
$scope.$digest()
2828
el
2929

30-
find = (el, selector) ->
31-
el[0].querySelector selector
32-
33-
firstNameEl = (el) ->
34-
find el, '[name=firstName]'
35-
36-
expectFormGroupHasErrorClass = (el) ->
37-
formGroup = el[0].querySelector '[id=first-name-group]'
38-
expect angular.element(formGroup).hasClass('has-error')
39-
4030
describe 'directive does not contain an input element with a name attribute', ->
4131
it 'throws an exception', ->
4232
expect( ->
@@ -63,7 +53,6 @@ describe 'showErrors', ->
6353
el = compileEl()
6454
$scope.userForm.firstName.$setViewValue invalidName
6555
angular.element(firstNameEl(el)).triggerHandler 'blur'
66-
$scope.$digest()
6756
expectFormGroupHasErrorClass(el).toBe true
6857

6958
describe '$dirty && $invalid && not blurred', ->
@@ -178,3 +167,127 @@ describe 'showErrors', ->
178167
$scope.$broadcast 'show-errors-reset'
179168
$timeout.flush()
180169
expectFormGroupHasErrorClass(el).toBe false
170+
171+
describe '{showSuccess: true} option', ->
172+
describe '$pristine && $valid', ->
173+
it 'has-success is absent', ->
174+
el = compileEl()
175+
expectLastNameFormGroupHasSuccessClass(el).toBe false
176+
177+
describe '$dirty && $valid && blurred', ->
178+
it 'has-success is present', ->
179+
el = compileEl()
180+
$scope.userForm.lastName.$setViewValue validName
181+
angular.element(lastNameEl(el)).triggerHandler 'blur'
182+
$scope.$digest()
183+
expectLastNameFormGroupHasSuccessClass(el).toBe true
184+
185+
describe '$dirty && $invalid && blurred', ->
186+
it 'has-success is present', ->
187+
el = compileEl()
188+
$scope.userForm.lastName.$setViewValue invalidName
189+
angular.element(lastNameEl(el)).triggerHandler 'blur'
190+
$scope.$digest()
191+
expectLastNameFormGroupHasSuccessClass(el).toBe false
192+
193+
describe '$invalid && blurred then becomes $valid before blurred', ->
194+
it 'has-success is present', ->
195+
el = compileEl()
196+
$scope.userForm.lastName.$setViewValue invalidName
197+
angular.element(lastNameEl(el)).triggerHandler 'blur'
198+
$scope.$apply ->
199+
$scope.userForm.lastName.$setViewValue invalidName
200+
$scope.$apply ->
201+
$scope.userForm.lastName.$setViewValue validName
202+
expectLastNameFormGroupHasSuccessClass(el).toBe true
203+
204+
describe '$valid && showErrorsCheckValidity is set before blurred', ->
205+
it 'has-success is present', ->
206+
el = compileEl()
207+
$scope.userForm.lastName.$setViewValue validName
208+
$scope.$broadcast 'show-errors-check-validity'
209+
expectLastNameFormGroupHasSuccessClass(el).toBe true
210+
211+
describe 'showErrorsReset', ->
212+
it 'removes has-success', ->
213+
el = compileEl()
214+
$scope.userForm.lastName.$setViewValue validName
215+
angular.element(lastNameEl(el)).triggerHandler 'blur'
216+
$scope.$broadcast 'show-errors-reset'
217+
$timeout.flush()
218+
expectLastNameFormGroupHasSuccessClass(el).toBe false
219+
220+
describe 'showErrorsConfig', ->
221+
$compile = undefined
222+
$scope = undefined
223+
$timeout = undefined
224+
validName = 'Paul'
225+
invalidName = 'Pa'
226+
227+
beforeEach ->
228+
testModule = angular.module 'testModule', []
229+
testModule.config (showErrorsConfigProvider) ->
230+
showErrorsConfigProvider.showSuccess true
231+
232+
module 'ui.bootstrap.showErrors', 'testModule'
233+
234+
inject((_$compile_, _$rootScope_, _$timeout_) ->
235+
$compile = _$compile_
236+
$scope = _$rootScope_
237+
$timeout = _$timeout_
238+
)
239+
240+
compileEl = ->
241+
el = $compile(
242+
'<form name="userForm">
243+
<div id="first-name-group" class="form-group" show-errors="{showSuccess: false}">
244+
<input type="text" name="firstName" ng-model="firstName" ng-minlength="3" />
245+
</div>
246+
<div id="last-name-group" class="form-group" show-errors>
247+
<input type="text" name="lastName" ng-model="lastName" ng-minlength="3" />
248+
</div>
249+
</form>'
250+
)($scope)
251+
angular.element(document.body).append el
252+
$scope.$digest()
253+
el
254+
255+
describe 'when showErrorsConfig.showSuccess is true', ->
256+
describe 'and no options given', ->
257+
it 'show-success class is applied', ->
258+
el = compileEl()
259+
$scope.userForm.lastName.$setViewValue validName
260+
angular.element(lastNameEl(el)).triggerHandler 'blur'
261+
$scope.$digest()
262+
expectLastNameFormGroupHasSuccessClass(el).toBe true
263+
264+
describe 'when showErrorsConfig.showSuccess is true', ->
265+
describe 'but options.showSuccess is false', ->
266+
it 'show-success class is not applied', ->
267+
el = compileEl()
268+
$scope.userForm.firstName.$setViewValue validName
269+
angular.element(firstNameEl(el)).triggerHandler 'blur'
270+
$scope.$digest()
271+
expectFirstNameFormGroupHasSuccessClass(el).toBe false
272+
273+
find = (el, selector) ->
274+
el[0].querySelector selector
275+
276+
firstNameEl = (el) ->
277+
find el, '[name=firstName]'
278+
279+
lastNameEl = (el) ->
280+
find el, '[name=lastName]'
281+
282+
expectFormGroupHasErrorClass = (el) ->
283+
formGroup = el[0].querySelector '[id=first-name-group]'
284+
expect angular.element(formGroup).hasClass('has-error')
285+
286+
expectFirstNameFormGroupHasSuccessClass = (el) ->
287+
formGroup = el[0].querySelector '[id=first-name-group]'
288+
expect angular.element(formGroup).hasClass('has-success')
289+
290+
expectLastNameFormGroupHasSuccessClass = (el) ->
291+
formGroup = el[0].querySelector '[id=last-name-group]'
292+
expect angular.element(formGroup).hasClass('has-success')
293+

0 commit comments

Comments
 (0)