aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/directive/form.js3
-rw-r--r--src/directive/input.js19
-rw-r--r--test/directive/inputSpec.js52
3 files changed, 39 insertions, 35 deletions
diff --git a/src/directive/form.js b/src/directive/form.js
index a1bfcd12..6bb1b4d6 100644
--- a/src/directive/form.js
+++ b/src/directive/form.js
@@ -4,7 +4,8 @@
var nullFormCtrl = {
$addControl: noop,
$removeControl: noop,
- $setValidity: noop
+ $setValidity: noop,
+ $setDirty: noop
}
/**
diff --git a/src/directive/input.js b/src/directive/input.js
index fee7a082..a92ad306 100644
--- a/src/directive/input.js
+++ b/src/directive/input.js
@@ -742,8 +742,8 @@ var inputDirective = [function() {
* @description
*
*/
-var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel',
- function($scope, $exceptionHandler, $attr, ngModel) {
+var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel', '$element',
+ function($scope, $exceptionHandler, $attr, ngModel, $element) {
this.$viewValue = Number.NaN;
this.$modelValue = Number.NaN;
this.$parsers = [];
@@ -757,6 +757,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel',
this.$render = noop;
this.$name = $attr.name;
+ var parentForm = $element.inheritedData('$formController') || nullFormCtrl;
/**
* @ngdoc function
@@ -789,9 +790,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel',
this.$valid = false;
}
- if (this.$form) {
- this.$form.$setValidity(validationErrorKey, isValid, this);
- }
+ parentForm.$setValidity(validationErrorKey, isValid, this);
};
@@ -819,7 +818,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', 'ngModel',
if (this.$pristine) {
this.$dirty = true;
this.$pristine = false;
- if (this.$form) this.$form.$setDirty();
+ parentForm.$setDirty();
}
forEach(this.$parsers, function(fn) {
@@ -907,11 +906,9 @@ var ngModelDirective = [function() {
// notify others, especially parent forms
var modelCtrl = ctrls[0],
- formCtrl = ctrls[1];
-
- modelCtrl.$form = formCtrl;
+ formCtrl = ctrls[1] || nullFormCtrl;
- if (formCtrl) formCtrl.$addControl(modelCtrl);
+ formCtrl.$addControl(modelCtrl);
forEach(['valid', 'invalid', 'pristine', 'dirty'], function(name) {
scope.$watch(function() {
@@ -922,7 +919,7 @@ var ngModelDirective = [function() {
});
element.bind('$destroy', function() {
- if (formCtrl) formCtrl.$removeControl(modelCtrl);
+ formCtrl.$removeControl(modelCtrl);
});
}
};
diff --git a/test/directive/inputSpec.js b/test/directive/inputSpec.js
index d68f6c54..4bdba36a 100644
--- a/test/directive/inputSpec.js
+++ b/test/directive/inputSpec.js
@@ -1,15 +1,24 @@
'use strict';
describe('NgModelController', function() {
- var ctrl, scope, ngModelAccessor;
+ var ctrl, scope, ngModelAccessor, element, parentFormCtrl;
beforeEach(inject(function($rootScope, $controller) {
var attrs = {name: 'testAlias'};
+ parentFormCtrl = {
+ $setValidity: jasmine.createSpy('$setValidity'),
+ $setDirty: jasmine.createSpy('$setDirty')
+ }
+
+ element = jqLite('<form><input></form>');
+ element.data('$formController', parentFormCtrl);
+
scope = $rootScope;
ngModelAccessor = jasmine.createSpy('ngModel accessor');
- ctrl = $controller(NgModelController, {$scope: scope, ngModel: ngModelAccessor, $attrs: attrs});
-
+ ctrl = $controller(NgModelController, {
+ $scope: scope, $element: element.find('input'), ngModel: ngModelAccessor, $attrs: attrs
+ });
// mock accessor (locals)
ngModelAccessor.andCallFake(function(val) {
if (isDefined(val)) scope.value = val;
@@ -18,6 +27,11 @@ describe('NgModelController', function() {
}));
+ afterEach(function() {
+ dealoc(element);
+ });
+
+
it('should init the properties', function() {
expect(ctrl.$dirty).toBe(false);
expect(ctrl.$pristine).toBe(true);
@@ -37,15 +51,13 @@ describe('NgModelController', function() {
describe('setValidity', function() {
it('should propagate invalid to the parent form only when valid', function() {
- var spy = jasmine.createSpy('setValidity');
- ctrl.$form = {$setValidity: spy};
-
+ expect(parentFormCtrl.$setValidity).not.toHaveBeenCalled();
ctrl.$setValidity('ERROR', false);
- expect(spy).toHaveBeenCalledOnceWith('ERROR', false, ctrl);
+ expect(parentFormCtrl.$setValidity).toHaveBeenCalledOnceWith('ERROR', false, ctrl);
- spy.reset();
+ parentFormCtrl.$setValidity.reset();
ctrl.$setValidity('ERROR', false);
- expect(spy).not.toHaveBeenCalled();
+ expect(parentFormCtrl.$setValidity).not.toHaveBeenCalled();
});
@@ -78,17 +90,14 @@ describe('NgModelController', function() {
it('should emit $valid only when $invalid', function() {
- var spy = jasmine.createSpy('setValidity');
- ctrl.$form = {$setValidity: spy};
-
ctrl.$setValidity('ERROR', true);
- expect(spy).not.toHaveBeenCalled();
+ expect(parentFormCtrl.$setValidity).not.toHaveBeenCalled();
ctrl.$setValidity('ERROR', false);
- expect(spy).toHaveBeenCalledOnceWith('ERROR', false, ctrl);
- spy.reset();
+ expect(parentFormCtrl.$setValidity).toHaveBeenCalledOnceWith('ERROR', false, ctrl);
+ parentFormCtrl.$setValidity.reset();
ctrl.$setValidity('ERROR', true);
- expect(spy).toHaveBeenCalledOnceWith('ERROR', true, ctrl);
+ expect(parentFormCtrl.$setValidity).toHaveBeenCalledOnceWith('ERROR', true, ctrl);
});
});
@@ -147,20 +156,17 @@ describe('NgModelController', function() {
});
- it('should call parentForm.setDirty only when pristine', function() {
- var spy = jasmine.createSpy('setDirty');
- ctrl.$form = {$setDirty: spy};
-
+ it('should call parentForm.$setDirty only when pristine', function() {
ctrl.$setViewValue('');
expect(ctrl.$pristine).toBe(false);
expect(ctrl.$dirty).toBe(true);
- expect(spy).toHaveBeenCalledOnce();
+ expect(parentFormCtrl.$setDirty).toHaveBeenCalledOnce();
- spy.reset();
+ parentFormCtrl.$setDirty.reset();
ctrl.$setViewValue('');
expect(ctrl.$pristine).toBe(false);
expect(ctrl.$dirty).toBe(true);
- expect(spy).not.toHaveBeenCalled();
+ expect(parentFormCtrl.$setDirty).not.toHaveBeenCalled();
});
});