diff options
| -rw-r--r-- | src/Angular.js | 10 | ||||
| -rw-r--r-- | src/Compiler.js | 1 | ||||
| -rw-r--r-- | src/Validators.js | 31 | ||||
| -rw-r--r-- | src/Widgets.js | 8 | ||||
| -rw-r--r-- | test/ValidatorsTest.js | 27 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 4 |
6 files changed, 50 insertions, 31 deletions
diff --git a/src/Angular.js b/src/Angular.js index 12293ddb..e49eb9a9 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -228,6 +228,16 @@ function escapeHtml(html) { replace(/>/g, '>'); } +function elementDecorateError(element, error) { + if (error) { + element.addClass(NG_VALIDATION_ERROR); + element.attr(NG_ERROR, error); + } else { + element.removeClass(NG_VALIDATION_ERROR); + element.removeAttr(NG_ERROR); + } +} + function escapeAttr(html) { if (!html || !html.replace) return html; diff --git a/src/Compiler.js b/src/Compiler.js index 923f7b2f..e97fb112 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -93,6 +93,7 @@ Compiler.prototype = { rawElement = jqLite(rawElement); var template = this.templatize(rawElement) || new Template(); return function(element, parentScope){ + element = jqLite(element); parentScope = parentScope || {}; var scope = createScope(parentScope); parentScope.$root = parentScope.$root || scope; diff --git a/src/Validators.js b/src/Validators.js index 662145c0..ecf21a01 100644 --- a/src/Validators.js +++ b/src/Validators.js @@ -82,29 +82,30 @@ foreach({ }, 'asynchronous': function(text, asynchronousFn) { - var stateKey = '$validateState'; - var lastKey = '$lastKey'; - var obj = this['$element']; - var stateCache = obj[stateKey] = obj[stateKey] || {}; - var state = stateCache[text]; - var updateView = this['$updateView']; - obj[lastKey] = text; + var element = this['$element']; + var cache = element.data('$validateState'); + if (!cache) { + cache = { state: {}}; + element.data('$validateState', cache); + } + var state = cache.state[text]; + cache.lastKey = text; if (state === undefined) { // we have never seen this before, Request it - jqLite(obj).addClass('ng-input-indicator-wait'); - state = stateCache[text] = null; - asynchronousFn(text, function(error){ - state = stateCache[text] = error ? error : false; - if (stateCache[obj[lastKey]] !== null) { - jqLite(obj).removeClass('ng-input-indicator-wait'); + element.addClass('ng-input-indicator-wait'); + state = cache.state[text] = null; + (asynchronousFn || noop)(text, function(error){ + state = cache.state[text] = error ? error : false; + if (cache.state[cache.lastKey] !== null) { + element.removeClass('ng-input-indicator-wait'); } - updateView(); + elementDecorateError(element, error); }); } if (state === null){ // request in flight, mark widget invalid, but don't show it to user - this['$invalidWidgets'].push(this.$element); + (this['$invalidWidgets']||[]).push(this.$element); } return state; } diff --git a/src/Widgets.js b/src/Widgets.js index b5222ac7..870468d3 100644 --- a/src/Widgets.js +++ b/src/Widgets.js @@ -28,13 +28,7 @@ function valueAccessor(scope, element) { function validate(value) { var error = required && !trim(value) ? "Required" : validator({self:scope, scope:{get:scope.$get, set:scope.$set}}, value); if (error !== lastError) { - if (error) { - element.addClass(NG_VALIDATION_ERROR); - element.attr(NG_ERROR, error); - } else { - element.removeClass(NG_VALIDATION_ERROR); - element.removeAttr(NG_ERROR); - } + elementDecorateError(element, error); lastError = error; } return value; diff --git a/test/ValidatorsTest.js b/test/ValidatorsTest.js index 971ff0bb..37be526d 100644 --- a/test/ValidatorsTest.js +++ b/test/ValidatorsTest.js @@ -91,24 +91,35 @@ describe('Validator:asynchronous', function(){ value = null; fn = null; self = { - $element:jqLite('<input />')[0], + $element:jqLite('<input />'), $invalidWidgets:[], $updateView: noop }; }); - xit('should make a request and show spinner', function(){ - var x = compile('<input name="name" ng-validate="asynchronous:asyncFn"/>'); - var asyncFn = function(v,f){value=v; fn=f;}; - var input = x.node.find(":input"); - x.scope.$set("asyncFn", asyncFn); - x.scope.$set("name", "misko"); - x.scope.$eval(); + afterEach(function(){ + if (self.$element) self.$element.remove(); + var oldCache = jqCache; + jqCache = {}; + expect(size(oldCache)).toEqual(0); + }); + + it('should make a request and show spinner', function(){ + var value, fn; + var scope = angular.compile('<input type="text" name="name" ng-validate="asynchronous:asyncFn"/>'); + scope.$init(); + var input = scope.$element; + scope.asyncFn = function(v,f){ + value=v; fn=f; + }; + scope.name = "misko"; + scope.$eval(); expect(value).toEqual('misko'); expect(input.hasClass('ng-input-indicator-wait')).toBeTruthy(); fn("myError"); expect(input.hasClass('ng-input-indicator-wait')).toBeFalsy(); expect(input.attr('ng-error')).toEqual("myError"); + scope.$element.remove(); }); it("should not make second request to same value", function(){ diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index dd65b5bd..152b01f3 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -15,7 +15,9 @@ describe("input widget", function(){ afterEach(function(){ if (element) element.remove(); - expect(size(jqCache)).toEqual(0); + var oldCache = jqCache; + jqCache = {}; + expect(size(oldCache)).toEqual(0); }); it('should input-text auto init and handle keyup/change events', function(){ |
