我一直在使用Beta版本1.3,现在移至1.3.1之后,我注意到一个问题,通过检查所有较早的版本,我发现它似乎已从 1.3.0 rc1 中启动。
我有这样的代码:
<select ng-model="home.modal.topicId"
ng-change="ctrl.modalTopicChanged()"
ng-options="item.id as item.name for item in home.modal.option.topics.data"
ng-required="true">
<option style="display: none;" value="">Select Topic</option>
</select>
在rc1之前,当表单首次显示时,未将ngt_strong更改为。现在,它使用 undefined 的home.modal.topicId触发。对我来说,这是一个重大更改,但在重大更改部分中未提及,我想知道这是否是一个尚未被发现的错误。
这是生成的堆栈跟踪:
TypeError: Cannot read property 'dataMap' of undefined
at AdminProblemController.modalTopicChanged (http://127.0.0.1:17315/Content/app/admin/controllers/ProblemController.js:109:114)
at $parseFunctionCall (http://127.0.0.1:17315/Scripts/angular.js:11387:18)
at Scope.$get.Scope.$eval (http://127.0.0.1:17315/Scripts/angular.js:13276:28)
at http://127.0.0.1:17315/Scripts/angular.js:19888:13
at http://127.0.0.1:17315/Scripts/angular.js:19499:9
at forEach (http://127.0.0.1:17315/Scripts/angular.js:331:20)
at $$writeModelToScope (http://127.0.0.1:17315/Scripts/angular.js:19497:5)
at writeToModelIfNeeded (http://127.0.0.1:17315/Scripts/angular.js:19490:14)
at http://127.0.0.1:17315/Scripts/angular.js:19484:9
at validationDone (http://127.0.0.1:17315/Scripts/angular.js:19420:9)
我在这里注意到的是一个新函数:writeToModelIfNeeded
当我查看更改日志差异时,当我检查所有更改和行号时,找不到对引入此功能的任何提及。
我想就此寻求一些建议。首先,可以找到导致增加writeToModelIfNeeded的更改,其次,这是选择框的正确功能。我认为整个想法是,只有在定义模型值的情况下,ng-change才会触发。
作为引用,以下是似乎已在1.3.0 rc.1中添加的新代码区域。
**
* @ngdoc method
* @name ngModel.NgModelController#$commitViewValue
*
* @description
* Commit a pending update to the `$modelValue`.
*
* Updates may be pending by a debounced event or because the input is waiting for a some future
* event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
* usually handles calling this in response to input events.
*/
this.$commitViewValue = function() {
var viewValue = ctrl.$viewValue;
$timeout.cancel(pendingDebounce);
// If the view value has not changed then we should just exit, except in the case where there is
// a native validator on the element. In this case the validation state may have changed even though
// the viewValue has stayed empty.
if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
return;
}
ctrl.$$lastCommittedViewValue = viewValue;
// change to dirty
if (ctrl.$pristine) {
ctrl.$dirty = true;
ctrl.$pristine = false;
$animate.removeClass($element, PRISTINE_CLASS);
$animate.addClass($element, DIRTY_CLASS);
parentForm.$setDirty();
}
this.$$parseAndValidate();
};
this.$$parseAndValidate = function() {
var parserValid = true,
viewValue = ctrl.$$lastCommittedViewValue,
modelValue = viewValue;
for(var i = 0; i < ctrl.$parsers.length; i++) {
modelValue = ctrl.$parsers[i](modelValue);
if (isUndefined(modelValue)) {
parserValid = false;
break;
}
}
if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
// ctrl.$modelValue has not been touched yet...
ctrl.$modelValue = ngModelGet();
}
var prevModelValue = ctrl.$modelValue;
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
if (allowInvalid) {
ctrl.$modelValue = modelValue;
writeToModelIfNeeded();
}
ctrl.$$runValidators(parserValid, modelValue, viewValue, function() {
if (!allowInvalid) {
ctrl.$modelValue = ctrl.$valid ? modelValue : undefined;
writeToModelIfNeeded();
}
});
function writeToModelIfNeeded() {
if (ctrl.$modelValue !== prevModelValue) {
ctrl.$$writeModelToScope();
}
}
};
this.$$writeModelToScope = function() {
ngModelSet(ctrl.$modelValue);
forEach(ctrl.$viewChangeListeners, function(listener) {
try {
listener();
} catch(e) {
$exceptionHandler(e);
}
});
};
最佳答案
通过执行此操作,我可以重现您的问题。在不知道您的 Controller 的情况下,虽然不确定是否相同:
this.modal = {
topicId:null,
option:{
topics:{
data:[{id:1,name:'item1'},{id:2,name:'item2'}]
}
}
};
这里发生的是angular表示null为无效值,因此默认情况下将其设置为undefined。您可以通过将其设置为“未定义”或将其添加到html中来解决此问题:
ng-model-options="{allowInvalid:true}"
还测试了Josep plunker,并将该值更改为null也导致ngChange触发