第一个点,要了解下:
DOM value
$viewValue
$modelValue
scope上挂载的属性的值
平常有2个流程:
$viewValue -->> $modelValue -->> scope
上挂载的属性的值scope上挂载的属性的值
-->> $modelValue -->> $viewValue
ngModel
经常运用的场景就是假如你运用第三方的插件比方时刻插件,每次挑选时刻后都是更新DOM value
的值,这个时刻DOM value
上的值事实上是你须要绑定到scope
属性上的值。那末这个时刻就须要ngModelController
。
在第一个流程当中,比方我加载了一个时刻插件:pikaday
html:
<div class="container" ng-controller="demoCtrl">
<p>挑选的时刻为: {{date.from}}</p>
<time-picker
ng-model="date.from"
></time-picker>
</div>
js:
angular.module('demoApp', []).controller('demoCtrl', function($scope) {
$scope.date = {
from: ''
};
$scope.$watch('date.from', function(val) {
console.log(val);
});
})
.directive('testDirective', ['$timeout', function($timeout) {
return {
restrict: 'EA',
require: '?ngModel',
link: function(scope, ele, attrs, ngModel) {
template: '<input type="text" id="pikadayTimerPicker">',
link: function (scope, ele, attr, ngModel) {
var picker = new Pikaday({
field: $('#pikadayTimerPicker')[0],
firstDay: 0,
yearRange: [2000, 2020],
format: 'YYYY-MM-DD',
hours24format : false,
showTime : true,
splitTimeView : true,
showSeconds : true,
minutesStep : 5,
i18n: {
previousMonth : '上月',
nextMonth : '下月',
months : ['一月','二月','三月','四月','五月','六月','七月','八月','玄月','十月','十一月','十二月'],
weekdays : ['周日','周一','周二','周三','周四','周五','周六'],
weekdaysShort : ['日','一','二','三','四','五','六']
},
onSelect: function () {
if(!ngModel) return; //假如ngModel不存在
ngModel.$setViewValue(this._d);
}
});
}
}
}
})
在onSelect
回调事宜内里,挪用了ngModel.$setViewValue
要领,它的作用就是使DOM value
–>> $viewValue
–>> $modelValue
–>> scope
上绑定的属性.
第二个流程当中,比方你须要初始化一个时刻,这个时刻多是从你背景调过来的,或者是猎取的当地的时刻.那末你起首要绑定scope
上的属性值,然则这个时刻在时刻插件上面显现的时刻并非scope
上绑定的属性值,这个时刻就须要$render
要领了:
$scope.data.from = $filter(new Date().valueOf())('YYYY-MM-DD hh:mm:ss');
xxxxx
var picker = new Picker({ xxxx });
//这个处所挪用
ngModel.$render = function() {
$('#pikadayTimerPicker').val(ngModel.$viewValue);
}
xxxxx
这里实行的流程就是:
scope上绑定的属性值发生变化 –>> $modelValue –>> $viewValue –>> 挪用$(‘#pikadayTimerPicker’).val(ngModel.$viewValue)去更新DOM value.
在2个流程当中还应该注重一些处所:
第一个流程当中会经由$parsers, $validators2个管道。
第二个流程当中会经由$formatters,$render, $validators 3个管道。
关于$parses, $formatters , $validators 3个管道的用法会在下一篇内里讲。
这里着重讲一下源码里的$render要领(文档23189行),
ctrl.$render = function() {
// Workaround for Firefox validation #12102.
var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
if (element.val() !== value) {
element.val(value);
}
};
这里就是起首推断$viewValue
是不是为空,然后再推断当前元素的DOM Value
和$viewValue
是不是一样,再挑选是不是更新视图。
别的就是须要注重的一个处所(文档26947行):
$scope.$watch(function ngModelWatch() {
var modelValue = ngModelGet($scope); //猎取scope上绑定的ng-model的值
// if scope model value and ngModel value are out of sync
// TODO(perf): why not move this to the action fn?
if (modelValue !== ctrl.$modelValue &&
// checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
(ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
) {
ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
parserValid = undefined;
var formatters = ctrl.$formatters,
idx = formatters.length;
var viewValue = modelValue;
while (idx--) {
viewValue = formatters[idx](viewValue);
}
if (ctrl.$viewValue !== viewValue) {
ctrl.$$updateEmptyClasses(viewValue);
ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
ctrl.$render();
ctrl.$$runValidators(modelValue, viewValue, noop);
}
}
return modelValue;
});
$render
要领平常是当ng-model
的值发生变化的时刻就会触发:
比方
ng-model
直接放在input
,select
标签内,那末ng
会自动响应ng-model
变化后,便会触发这个要领,来使Dom
和$scope
上挂载的属性值坚持雷同.指令内部封装了
input
标签,然则ng-model
是在指令外部的外部标签下时。平常须要经由过程event handler
去挪用ngModel.$setViewValue
要领去时DOM Value
和scope
上挂载的属性值坚持一致。详细的demo就如上例。
ngModel.$render
要领是能够从新自定义的:
ngModel.$render = function() {
// scope上的属性值,$modelValue, $viewValue已发生变化
// 应用这些值再次能够再次做响应的处置惩罚,然后更新DOM value
}
抽时刻把关于ngModel再补上。睡觉。
参考资料: