controller.$viewValue/controller.$modelValue 有什么意义?
What is the point of controller.$viewValue/controller.$modelValue?
我不清楚scope.ngModel
和controller.$viewValue
/controller.$modelValue
/controller.$setViewValue()
之间的关系是什么,具体来说,后三者的意义是什么.例如,参见 this jsfiddle:
<input type="text" ng-model="foo" my-directive>
和:
myApp.directive('myDirective', function($timeout) {
return {
require: 'ngModel',
restrict: 'A',
scope: { ngModel: '=' },
link: function (scope, element, attrs, controller) {
function log() {
console.log(scope.ngModel);
console.log(controller.$viewValue);
console.log(controller.$modelValue);
}
log();
controller.$setViewValue("boorb");
log();
scope.$watch('ngModel', function (val) {
console.log("val is now", val);
});
$timeout(function () {
log();
}, 2000);
}
}
});
控制器为:
function MyCtrl($scope, $timeout) {
$scope.foo = 'ahha';
$timeout(function () {
$scope.foo = "good";
}, 1000);
}
输出为:
(index):45 ahha
(index):46 NaN
(index):47 NaN
(index):45 ahha
(index):46 boorb
(index):47 boorb
(index):53 val is now ahha
(index):53 val is now good
(index):45 good
(index):46 boorb
(index):47 boorb
controller.$viewValue
并不是作为 foo
变量的值开始的。此外,controller.$setViewValue("boorb")
根本没有影响 scope.ngModel
,更新也没有反映在 HTML 中。因此,scope.ngModel
和controller.$viewValue
之间似乎没有关系。似乎无论我想做什么,我都会使用 scope.ngModel
,然后观察这些值。使用 controller.$viewValue
和 controller.$modelValue
或使它们与 scope.ngModel
保持同步有什么意义?
scope: { ngModel: '=' },
为指令创建一个独立的作用域,这意味着指令中对 foo
的更改将不再反映在 MyCtrl
.[=18 的父作用域中=]
此外,$setViewValue()
所做的更改不会反映在 DOM 中,直到 controller.$render()
被调用,这告诉 Angular 更新 DOM在下一个摘要周期中。
但要回答这个问题,NgModelController
及其方法实际上只有在您需要创建一些特殊的自定义花式数据绑定指令时才是必需的。对于正常的数据输入和验证,您永远不需要使用它。来自 the documentation(强调我的):
[NgModelController] contains services for data-binding, validation, CSS updates, and value formatting and parsing. It purposefully does not contain any logic which deals with DOM rendering or listening to DOM events. Such DOM related logic should be provided by other directives which make use of NgModelController for data-binding to control elements. Angular provides this DOM logic for most input elements.
这里的混淆来自于将指令粘贴到现有指令上,即 ngInput
。
相反,考虑一个新指令:
<my-directive ng-model="ugh">Sup</my-directive>
有:
$rootScope.ugh = 40;
并且:
.directive('myDirective', function () {
return {
require: "ngModel",
// element-only directive
restrict: "E",
// template turns the directive into one input tag
// 'inner' is on the scope of the *directive*
template: "<input type='text' ng-model='inner'/>",
// the directive will have its own isolated scope
scope: { },
link: function (scope, element, attrs, ngModelCtrl) {
// formatter goes from modelValue (i.e. $rootScope.ugh) to
// view value (in this case, the string of twice the model
// value + '-'
ngModelCtrl.$formatters.push(function (modelValue) {
return ('' + (modelValue * 2)) + '-';
});
// render does what is necessary to display the view value
// in this case, sets the scope.inner so that the inner
// <input> can render it
ngModelCtrl.$render = function () {
scope.inner = ngModelCtrl.$viewValue;
};
// changes on the inner should trigger changes in the view value
scope.$watch('inner', function (newValue) {
ngModelCtrl.$setViewValue(newValue);
});
// when the view value changes, it gets parsed back into a model
// value via the parsers, which then sets the $modelValue, which
// then sets the underlying model ($rootScope.ugh)
ngModelCtrl.$parsers.push(function (viewValue) {
var sub = viewValue.substr(0, viewValue.length-1);
return parseInt(sub)/2;
});
}
};
})
在 Plunker 上试用。
请注意 typeof ugh
保持 "number"
,即使指令的视图值是不同的类型。
我不清楚scope.ngModel
和controller.$viewValue
/controller.$modelValue
/controller.$setViewValue()
之间的关系是什么,具体来说,后三者的意义是什么.例如,参见 this jsfiddle:
<input type="text" ng-model="foo" my-directive>
和:
myApp.directive('myDirective', function($timeout) {
return {
require: 'ngModel',
restrict: 'A',
scope: { ngModel: '=' },
link: function (scope, element, attrs, controller) {
function log() {
console.log(scope.ngModel);
console.log(controller.$viewValue);
console.log(controller.$modelValue);
}
log();
controller.$setViewValue("boorb");
log();
scope.$watch('ngModel', function (val) {
console.log("val is now", val);
});
$timeout(function () {
log();
}, 2000);
}
}
});
控制器为:
function MyCtrl($scope, $timeout) {
$scope.foo = 'ahha';
$timeout(function () {
$scope.foo = "good";
}, 1000);
}
输出为:
(index):45 ahha
(index):46 NaN
(index):47 NaN
(index):45 ahha
(index):46 boorb
(index):47 boorb
(index):53 val is now ahha
(index):53 val is now good
(index):45 good
(index):46 boorb
(index):47 boorb
controller.$viewValue
并不是作为 foo
变量的值开始的。此外,controller.$setViewValue("boorb")
根本没有影响 scope.ngModel
,更新也没有反映在 HTML 中。因此,scope.ngModel
和controller.$viewValue
之间似乎没有关系。似乎无论我想做什么,我都会使用 scope.ngModel
,然后观察这些值。使用 controller.$viewValue
和 controller.$modelValue
或使它们与 scope.ngModel
保持同步有什么意义?
scope: { ngModel: '=' },
为指令创建一个独立的作用域,这意味着指令中对 foo
的更改将不再反映在 MyCtrl
.[=18 的父作用域中=]
此外,$setViewValue()
所做的更改不会反映在 DOM 中,直到 controller.$render()
被调用,这告诉 Angular 更新 DOM在下一个摘要周期中。
但要回答这个问题,NgModelController
及其方法实际上只有在您需要创建一些特殊的自定义花式数据绑定指令时才是必需的。对于正常的数据输入和验证,您永远不需要使用它。来自 the documentation(强调我的):
[NgModelController] contains services for data-binding, validation, CSS updates, and value formatting and parsing. It purposefully does not contain any logic which deals with DOM rendering or listening to DOM events. Such DOM related logic should be provided by other directives which make use of NgModelController for data-binding to control elements. Angular provides this DOM logic for most input elements.
这里的混淆来自于将指令粘贴到现有指令上,即 ngInput
。
相反,考虑一个新指令:
<my-directive ng-model="ugh">Sup</my-directive>
有:
$rootScope.ugh = 40;
并且:
.directive('myDirective', function () {
return {
require: "ngModel",
// element-only directive
restrict: "E",
// template turns the directive into one input tag
// 'inner' is on the scope of the *directive*
template: "<input type='text' ng-model='inner'/>",
// the directive will have its own isolated scope
scope: { },
link: function (scope, element, attrs, ngModelCtrl) {
// formatter goes from modelValue (i.e. $rootScope.ugh) to
// view value (in this case, the string of twice the model
// value + '-'
ngModelCtrl.$formatters.push(function (modelValue) {
return ('' + (modelValue * 2)) + '-';
});
// render does what is necessary to display the view value
// in this case, sets the scope.inner so that the inner
// <input> can render it
ngModelCtrl.$render = function () {
scope.inner = ngModelCtrl.$viewValue;
};
// changes on the inner should trigger changes in the view value
scope.$watch('inner', function (newValue) {
ngModelCtrl.$setViewValue(newValue);
});
// when the view value changes, it gets parsed back into a model
// value via the parsers, which then sets the $modelValue, which
// then sets the underlying model ($rootScope.ugh)
ngModelCtrl.$parsers.push(function (viewValue) {
var sub = viewValue.substr(0, viewValue.length-1);
return parseInt(sub)/2;
});
}
};
})
在 Plunker 上试用。
请注意 typeof ugh
保持 "number"
,即使指令的视图值是不同的类型。