diff --git a/src/showErrors.coffee b/src/showErrors.coffee index 4d66b4d..9f96fbd 100644 --- a/src/showErrors.coffee +++ b/src/showErrors.coffee @@ -16,36 +16,57 @@ showErrorsModule.directive 'showErrors', showSuccess linkFn = (scope, el, attrs, formCtrl) -> - blurred = false + blurred = {} + inputNames = [] options = scope.$eval attrs.showErrors showSuccess = getShowSuccess options - trigger = getTrigger options + trigger = getTrigger options - inputEl = el[0].querySelector '.form-control[name]' - inputNgEl = angular.element inputEl - inputName = $interpolate(inputNgEl.attr('name') || '')(scope) - unless inputName - throw "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class" + inputElements = {} + for inputElement in el[0].querySelectorAll('.form-control[name]') + if inputName = $interpolate(inputElement.name || '')(scope) + (inputElements[inputName] or= []).push inputElement + + isBlurred = () -> + allBlurred = true + angular.forEach blurred, (elementBlurred) -> + allBlurred = allBlurred && elementBlurred + allBlurred + + isValid = () -> + allValid = true + angular.forEach inputNames, (inputName) -> + allValid = allValid && formCtrl[inputName].$valid + allValid - inputNgEl.bind trigger, -> - blurred = true - toggleClasses formCtrl[inputName].$invalid + angular.forEach inputElements, (inputEl, inputName) -> + inputNames.push inputName + blurred[inputName] = false + inputNgEl = angular.element inputEl + inputNgEl.bind trigger, -> + blurred[inputName] = true + if isBlurred() + toggleClasses !isValid() - scope.$watch -> - formCtrl[inputName] && formCtrl[inputName].$invalid - , (invalid) -> - return if !blurred - toggleClasses invalid + scope.$watch -> + formCtrl[inputName] && formCtrl[inputName].$invalid + , (invalid) -> + return if !isBlurred() + toggleClasses !isValid() + + unless inputNames.length + throw "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class" scope.$on 'show-errors-check-validity', -> - toggleClasses formCtrl[inputName].$invalid + toggleClasses !isValid() scope.$on 'show-errors-reset', -> $timeout -> # want to run this after the current digest cycle el.removeClass 'has-error' el.removeClass 'has-success' - blurred = false + angular.forEach inputNames, (inputName) -> + blurred[inputName] = false , 0, false toggleClasses = (invalid) -> diff --git a/src/showErrors.js b/src/showErrors.js index 934f59b..51d287d 100644 --- a/src/showErrors.js +++ b/src/showErrors.js @@ -23,37 +23,69 @@ return showSuccess; }; linkFn = function(scope, el, attrs, formCtrl) { - var blurred, inputEl, inputName, inputNgEl, options, showSuccess, toggleClasses, trigger; - blurred = false; + var blurred, inputElement, inputElements, inputName, inputNames, isBlurred, isValid, options, showSuccess, toggleClasses, trigger, _i, _len, _ref; + blurred = {}; + inputNames = []; options = scope.$eval(attrs.showErrors); showSuccess = getShowSuccess(options); trigger = getTrigger(options); - inputEl = el[0].querySelector('.form-control[name]'); - inputNgEl = angular.element(inputEl); - inputName = $interpolate(inputNgEl.attr('name') || '')(scope); - if (!inputName) { - throw "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class"; - } - inputNgEl.bind(trigger, function() { - blurred = true; - return toggleClasses(formCtrl[inputName].$invalid); - }); - scope.$watch(function() { - return formCtrl[inputName] && formCtrl[inputName].$invalid; - }, function(invalid) { - if (!blurred) { - return; + inputElements = {}; + _ref = el[0].querySelectorAll('.form-control[name]'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + inputElement = _ref[_i]; + if (inputName = $interpolate(inputElement.name || '')(scope)) { + (inputElements[inputName] || (inputElements[inputName] = [])).push(inputElement); } - return toggleClasses(invalid); + } + isBlurred = function() { + var allBlurred; + allBlurred = true; + angular.forEach(blurred, function(elementBlurred) { + return allBlurred = allBlurred && elementBlurred; + }); + return allBlurred; + }; + isValid = function() { + var allValid; + allValid = true; + angular.forEach(inputNames, function(inputName) { + return allValid = allValid && formCtrl[inputName].$valid; + }); + return allValid; + }; + angular.forEach(inputElements, function(inputEl, inputName) { + var inputNgEl; + inputNames.push(inputName); + blurred[inputName] = false; + inputNgEl = angular.element(inputEl); + inputNgEl.bind(trigger, function() { + blurred[inputName] = true; + if (isBlurred()) { + return toggleClasses(!isValid()); + } + }); + return scope.$watch(function() { + return formCtrl[inputName] && formCtrl[inputName].$invalid; + }, function(invalid) { + if (!isBlurred()) { + return; + } + return toggleClasses(!isValid()); + }); }); + if (!inputNames.length) { + throw "show-errors element has no child input elements with a 'name' attribute and a 'form-control' class"; + } scope.$on('show-errors-check-validity', function() { - return toggleClasses(formCtrl[inputName].$invalid); + return toggleClasses(!isValid()); }); scope.$on('show-errors-reset', function() { return $timeout(function() { el.removeClass('has-error'); el.removeClass('has-success'); - return blurred = false; + return angular.forEach(inputNames, function(inputName) { + return blurred[inputName] = false; + }); }, 0, false); }); return toggleClasses = function(invalid) { diff --git a/src/showErrors.min.js b/src/showErrors.min.js index 72c5343..1bced51 100644 --- a/src/showErrors.min.js +++ b/src/showErrors.min.js @@ -1,2 +1,2 @@ -/*! angular-bootstrap-show-errors (version 2.3.0) 2015-01-19 */ -(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); \ No newline at end of file +/*! angular-bootstrap-show-errors (version 2.3.0) 2015-02-13 */ +(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,q,r,s,t,u,v;for(i={},m=[],p=b.$eval(g.showErrors),q=d(p),s=e(p),k={},v=f[0].querySelectorAll(".form-control[name]"),t=0,u=v.length;u>t;t++)j=v[t],(l=c(j.name||"")(b))&&(k[l]||(k[l]=[])).push(j);if(n=function(){var a;return a=!0,angular.forEach(i,function(b){return a=a&&b}),a},o=function(){var a;return a=!0,angular.forEach(m,function(b){return a=a&&h[b].$valid}),a},angular.forEach(k,function(a,c){var d;return m.push(c),i[c]=!1,d=angular.element(a),d.bind(s,function(){return i[c]=!0,n()?r(!o()):void 0}),b.$watch(function(){return h[c]&&h[c].$invalid},function(){return n()?r(!o()):void 0})}),!m.length)throw"show-errors element has no child input elements with a 'name' attribute and a 'form-control' class";return b.$on("show-errors-check-validity",function(){return r(!o())}),b.$on("show-errors-reset",function(){return a(function(){return f.removeClass("has-error"),f.removeClass("has-success"),angular.forEach(m,function(a){return i[a]=!1})},0,!1)}),r=function(a){return f.toggleClass("has-error",a),q?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); \ No newline at end of file diff --git a/test/showErrors.spec.coffee b/test/showErrors.spec.coffee index 5ead727..f750d12 100644 --- a/test/showErrors.spec.coffee +++ b/test/showErrors.spec.coffee @@ -21,6 +21,10 @@ describe 'showErrors', ->