-
Notifications
You must be signed in to change notification settings - Fork 27.4k
feat(input): interpolates form input name attrs for ngModel #4791
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should invoke There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no need to since all watchers are removed when the scope is destroyed. Internally There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not exactly --- the observers collection stays alive afaik. The attribute interpolation watches are removed automatically though, this is true There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's probably better to unobserve manually rather than accidentally risk keeping a reference alive There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whatever makes you guys happy :> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't add unobserve here, as we don't have it at similar places in the code neither and it confuses the reader (ask myself: "why here and not at the other places"...) |
||
parentFormCtrl.$removeControl(controller); | ||
if (alias) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the handling when there is no parent form (similar to the handling in
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should have a test for this as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've decided to have the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice |
||
} | ||
}); | ||
|
||
scope.$on('$destroy', function() { | ||
formCtrl.$removeControl(modelCtrl); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to: