Last active
May 3, 2016 17:02
-
-
Save jeff-kilbride/47c5342a5e458cc8fcbb0efbc341c3aa to your computer and use it in GitHub Desktop.
Adding bootstrap validation styling to angular with a custom directive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Directive for applying bootstrap validation styles. | |
/* | |
Sample HTML block. | |
<div class="form-group has-feedback" bs-style> | |
<label for="fName">First Name</label> | |
<input type="text" class="form-control" name="fName" id="fName" ng-model="vm.fName" | |
ng-minlength="2" ng-maxlength="20" required/> | |
<span class="form-control-feedback glyphicon"></span> | |
<span class="help-block ng-hide"></span> | |
</div> | |
Sample HTML block with "short" option. | |
<div class="form-group has-feedback" bs-style="short"> | |
<label for="fName">First Name</label> | |
<input type="text" class="form-control" name="fName" id="fName" ng-model="vm.fName" | |
ng-minlength="2" ng-maxlength="20" required/> | |
<span class="form-control-feedback glyphicon"></span> | |
<span class="help-block ng-hide"></span> | |
</div> | |
*/ | |
'use strict'; | |
angular | |
.module('app') | |
.directive('bsStyle', function() { | |
return { | |
restrict: 'A', | |
link: function(scope, element, attrs) { | |
// Find the input in this form-group. | |
for (var el of ['input', 'select', 'textarea']) { | |
var input = element.find(el); | |
if (!input.length) continue; | |
// Get the ngModelController for this input. | |
var ngm = input.controller('ngModel'); | |
// Add a $watchGroup to handle the bootstrap validation styling. | |
// Monitor the $valid, $dirty and $touched, and $error values | |
// independently, so the listener fires when any of them change. | |
scope.$watchGroup([ | |
function isValid() { return ngm.$valid; }, | |
function isTD() { return ngm.$touched && ngm.$dirty; }, | |
function hasError() { return Object.keys(ngm.$error).join(); } | |
], | |
function updateStyles(newValues, oldValues) { | |
// This should only happen in the initialization phase. Ignore it. | |
if (angular.equals(newValues, oldValues)) return; | |
// Don't do anything unless the input is $touched and $dirty. | |
if (!newValues[1]) return; | |
// Toggle the bootstrap 'has-success' and 'has-error' classes | |
// on the form-group based on $valid. | |
element.toggleClass('has-success', newValues[0]) | |
.toggleClass('has-error', !newValues[0]); | |
// Update the icons and error messages based on $valid and $error. | |
var spans = element.find('span'); | |
for (var i = 0; i < spans.length; i++) { | |
var s = spans.eq(i); | |
if (s.hasClass('form-control-feedback')) { | |
s.toggleClass('glyphicon-ok', newValues[0]) | |
.toggleClass('glyphicon-remove', !newValues[0]); | |
} | |
if (s.hasClass('help-block')) { | |
// Only update the error message when not $valid. | |
if (!newValues[0]) { | |
var label = element.find('label').text(), | |
short = attrs.bsStyle === 'short', | |
e = ngm.$error; | |
// Create an error message based on the triggered error, | |
// the 'short' attribute, and the form-group's label. | |
// Customize these based on the validations used. | |
if (short) { | |
if (e.required) s.text('Required.'); | |
else if (e.minlength) s.text('Too short.'); | |
else if (e.maxlength) s.text('Too long.'); | |
else if (e.mask) s.text('Not Valid.'); | |
} | |
else { | |
if (e.required) | |
s.text(label + ' is required.'); | |
else if (e.minlength) | |
s.text(label + ' must be at least ' + | |
input.attr('ng-minlength') + ' chars.'); | |
else if (e.maxlength) | |
s.text(label + ' must be less than ' + | |
input.attr('ng-maxlength') + ' chars.'); | |
else if (e.mask) | |
s.text(label + ' is not valid.'); | |
} | |
} | |
// Display / hide the message based on $valid. | |
s.toggleClass('ng-hide', newValues[0]); | |
} | |
} | |
} | |
); | |
// Stop any extra loop processing. | |
break; | |
} | |
} | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment