diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 3ee544ea2543..6772d93243d9 100644 --- a/src/ng/directive/form.js +++ b/src/ng/directive/form.js @@ -4,6 +4,7 @@ */ var nullFormCtrl = { $addControl: noop, + $$renameControl: nullFormRenameControl, $removeControl: noop, $setValidity: noop, $$setPending: noop, @@ -14,6 +15,10 @@ var nullFormCtrl = { }, SUBMITTED_CLASS = 'ng-submitted'; +function nullFormRenameControl(control, name) { + control.$name = name; +} + /** * @ngdoc type * @name form.FormController @@ -51,17 +56,18 @@ SUBMITTED_CLASS = 'ng-submitted'; * */ //asks for $scope to fool the BC controller module -FormController.$inject = ['$element', '$attrs', '$scope', '$animate']; -function FormController(element, attrs, $scope, $animate) { +FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate']; +function FormController(element, attrs, $scope, $animate, $interpolate) { var form = this, - parentForm = element.parent().controller('form') || nullFormCtrl, controls = []; + var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl; + // init state form.$error = {}; form.$$success = {}; form.$pending = undefined; - form.$name = attrs.name || attrs.ngForm; + form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope); form.$dirty = false; form.$pristine = true; form.$valid = true; @@ -127,6 +133,17 @@ function FormController(element, attrs, $scope, $animate) { } }; + // Private API: rename a form control + form.$$renameControl = function(control, newName) { + var oldName = control.$name; + + if (form[oldName] === control) { + delete form[oldName]; + } + form[newName] = control; + control.$name = newName; + }; + /** * @ngdoc method * @name form.FormController#$removeControl @@ -466,13 +483,20 @@ var formDirectiveFactory = function(isNgForm) { }); } - var parentFormCtrl = formElement.parent().controller('form'), - alias = attr.name || attr.ngForm; + var parentFormCtrl = controller.$$parentForm, + alias = controller.$name; if (alias) { setter(scope, alias, controller, alias); + attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) { + if (alias === newValue) return; + setter(scope, alias, undefined, alias); + alias = newValue; + setter(scope, alias, controller, alias); + parentFormCtrl.$$renameControl(controller, alias); + }); } - if (parentFormCtrl) { + if (parentFormCtrl !== nullFormCtrl) { formElement.on('$destroy', function() { parentFormCtrl.$removeControl(controller); if (alias) { diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index ba98a5a4cd17..4a50d502746e 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1657,8 +1657,8 @@ var VALID_CLASS = 'ng-valid', * * */ -var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', - function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q) { +var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate', + function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) { this.$viewValue = Number.NaN; this.$modelValue = Number.NaN; this.$validators = {}; @@ -1675,7 +1675,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ this.$error = {}; // keep invalid keys here this.$$success = {}; // keep valid keys here this.$pending = undefined; // keep pending keys here - this.$name = $attr.name; + this.$name = $interpolate($attr.name || '', false)($scope); var parsedNgModel = $parse($attr.ngModel), @@ -2387,6 +2387,12 @@ var ngModelDirective = function() { // notify others, especially parent forms formCtrl.$addControl(modelCtrl); + attr.$observe('name', function(newValue) { + if (modelCtrl.$name !== newValue) { + formCtrl.$$renameControl(modelCtrl, newValue); + } + }); + scope.$on('$destroy', function() { formCtrl.$removeControl(modelCtrl); }); diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index f843801d2735..4a82a01e6bb3 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -782,6 +782,57 @@ describe('form', function() { }); }); + + it('should rename nested form controls when interpolated name changes', function() { + scope.idA = 'A'; + scope.idB = 'X'; + + doc = $compile( + '