Я не знаю, какова связь между scope.ngModel
и controller.$viewValue
/controller.$modelValue
/controller.$setViewValue()
есть и, в частности, то, что точка последних трех. Например, см. Этот 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
?
Путаница здесь происходит от ngInput
директивы на существующую директиву, а именно на 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: '=' },
создает изолированную область действия для директивы, а это означает, что изменения в foo
в директиве больше не будут отображаться в родительской области MyCtrl
.
Кроме того, изменения, сделанные с помощью $setViewValue()
, не будут отображаться в DOM до controller.$render()
$setViewValue()
controller.$render()
, который сообщает Angular об обновлении DOM в следующем цикле дайджеста.
Но чтобы ответить на этот вопрос, NgModelController
и его методы действительно необходимы только в том случае, если вам нужно создать некоторые специальные специальные настройки для привязки данных. Для нормального ввода и проверки данных вам никогда не придется использовать его. Из документации (акцент мой):
[NgModelController] содержит службы для привязки данных, проверки, обновления CSS и форматирования и разбора значений. Он целенаправленно не содержит никакой логики, которая связана с рендерингом DOM или прослушиванием событий DOM. Такая логика, связанная с DOM, должна предоставляться другими директивами, которые используют NgModelController для привязки данных к элементам управления. Угловой обеспечивает эту логику DOM для большинства входных элементов.