diff options
| author | Misko Hevery | 2012-04-03 22:05:13 -0700 | 
|---|---|---|
| committer | Misko Hevery | 2012-04-03 23:28:05 -0700 | 
| commit | 21b77ad5c231ab0e05eb89f22005f7ed8d40a6c1 (patch) | |
| tree | 3425cfb53994ff0bc7a321144099a6a811f97259 | |
| parent | 2f5dba488e855bcdbb9304aa809efcb9de7b43e9 (diff) | |
| download | angular.js-21b77ad5c231ab0e05eb89f22005f7ed8d40a6c1.tar.bz2 | |
fix(form): preperly clean up when invalid widget is removed
Removing invalid widget sometimes resulted in improper cleanup of the form state.
| -rw-r--r-- | src/ng/directive/form.js | 61 | ||||
| -rw-r--r-- | test/ng/directive/formSpec.js | 43 | 
2 files changed, 66 insertions, 38 deletions
| diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 7b96c936..f688b542 100644 --- a/src/ng/directive/form.js +++ b/src/ng/directive/form.js @@ -70,23 +70,43 @@ function FormController(element, attrs) {      if (control.$name && form[control.$name] === control) {        delete form[control.$name];      } -    forEach(errors, cleanupControlErrors, control); +    forEach(errors, function(queue, validationToken) { +      form.$setValidity(validationToken, true, control); +    });    };    form.$setValidity = function(validationToken, isValid, control) { -    if (isValid) { -      cleanupControlErrors(errors[validationToken], validationToken, control); +    var queue = errors[validationToken]; -      if (!invalidCount) { -        toggleValidCss(isValid); -        form.$valid = true; -        form.$invalid = false; +    if (isValid) { +      if (queue) { +        arrayRemove(queue, control); +        if (!queue.length) { +          invalidCount--; +          if (!invalidCount) { +            toggleValidCss(isValid); +            form.$valid = true; +            form.$invalid = false; +          } +          errors[validationToken] = false; +          toggleValidCss(true, validationToken); +          parentForm.$setValidity(validationToken, true, form); +        }        } +      } else {        if (!invalidCount) {          toggleValidCss(isValid);        } -      addControlError(validationToken, control); +      if (queue) { +        if (includes(queue, control)) return; +      } else { +        errors[validationToken] = queue = []; +        invalidCount++; +        toggleValidCss(false, validationToken); +        parentForm.$setValidity(validationToken, false, form); +      } +      queue.push(control);        form.$valid = false;        form.$invalid = true; @@ -99,31 +119,6 @@ function FormController(element, attrs) {      form.$pristine = false;    }; -  function cleanupControlErrors(queue, validationToken, control) { -    if (queue) { -      control = control || this; // so that we can be used in forEach; -      arrayRemove(queue, control); -      if (!queue.length) { -        invalidCount--; -        errors[validationToken] = false; -        toggleValidCss(true, validationToken); -        parentForm.$setValidity(validationToken, true, form); -      } -    } -  } - -  function addControlError(validationToken, control) { -    var queue = errors[validationToken]; -    if (queue) { -      if (includes(queue, control)) return; -    } else { -      errors[validationToken] = queue = []; -      invalidCount++; -      toggleValidCss(false, validationToken); -      parentForm.$setValidity(validationToken, false, form); -    } -    queue.push(control); -  }  } diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index 491a31db..3e672a7b 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -189,16 +189,16 @@ describe('form', function() {      it('should deregister a child form when its DOM is removed', function() {        doc = jqLite( -          '<form name="parent">' + -            '<div class="ng-form" name="child">' + -              '<input ng:model="modelA" name="inputA" required>' + -            '</div>' + +        '<form name="parent">' + +          '<div class="ng-form" name="child">' + +          '<input ng:model="modelA" name="inputA" required>' + +          '</div>' +            '</form>');        $compile(doc)(scope);        scope.$apply();        var parent = scope.parent, -          child = scope.child; +        child = scope.child;        expect(parent).toBeDefined();        expect(child).toBeDefined(); @@ -211,6 +211,39 @@ describe('form', function() {      }); +    it('should deregister a input when its removed from DOM', function() { +      doc = jqLite( +        '<form name="parent">' + +          '<div class="ng-form" name="child">' + +            '<input ng:model="modelA" name="inputA" required>' + +          '</div>' + +        '</form>'); +      $compile(doc)(scope); +      scope.$apply(); + +      var parent = scope.parent, +          child = scope.child, +          input = child.inputA; + +      expect(parent).toBeDefined(); +      expect(child).toBeDefined(); +      expect(parent.$error.required).toEqual([child]); +      expect(child.$error.required).toEqual([input]); +      expect(doc.hasClass('ng-invalid')).toBe(true); +      expect(doc.hasClass('ng-invalid-required')).toBe(true); +      expect(doc.find('div').hasClass('ng-invalid')).toBe(true); +      expect(doc.find('div').hasClass('ng-invalid-required')).toBe(true); +      doc.find('input').remove(); //remove child + +      expect(parent.$error.required).toBe(false); +      expect(child.$error.required).toBe(false); +      expect(doc.hasClass('ng-valid')).toBe(true); +      expect(doc.hasClass('ng-valid-required')).toBe(true); +      expect(doc.find('div').hasClass('ng-valid')).toBe(true); +      expect(doc.find('div').hasClass('ng-valid-required')).toBe(true); +    }); + +      it('should chain nested forms in repeater', function() {        doc = jqLite(           '<ng:form name=parent>' + | 
