Javascript 自定义角度指令中的ng开关断开双向绑定
我创建了自定义指令来封装uib日期选择器弹出窗口:Javascript 自定义角度指令中的ng开关断开双向绑定,javascript,angularjs,datepicker,Javascript,Angularjs,Datepicker,我创建了自定义指令来封装uib日期选择器弹出窗口: 'use strict'; angular.module( 'frontendApp' ) .directive( 'inputDate', function(){ var controller = function(){ var vm = this; function init() { vm.formats = [ 'dd.MMMM yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDat
'use strict';
angular.module( 'frontendApp' )
.directive( 'inputDate', function(){
var controller = function(){
var vm = this;
function init() {
vm.formats = [ 'dd.MMMM yyyy', 'yyyy/MM/dd', 'dd.MM.yyyy', 'shortDate' ];
vm.format = vm.formats[ 0 ];
vm.altInputFormats = [ 'M!/d!/yyyy' ];
vm.dateOptions = {
datepickerMode: 'day',
formatYear: 'yy',
maxDate: new Date(),
minDate: new Date( 1900, 1, 1 ),
startingDay: 1
};
vm.datepicker = {
opened: false
};
};
init();
vm.showDatePicker = function(){
vm.datepicker.opened = true;
};
};
var template = '<div ng-switch on="readonly" >' +
'<div ng-switch-when="true" class="form-control" readonly>' +
'<div readonly name="readonlyText">{{ngModel | date : \'d.MMMM yyyy\'}}</div>' +
'</div>' +
'<div ng-switch-default class="input-group">' +
'<input class="form-control" type="text" uib-datepicker-popup="{{vm.format}}" ng-model="ngModel" ng-model-options="{timezone:\'UTC\'}" is-open="vm.datepicker.opened" datepicker-options="vm.dateOptions" ng-required="true" show-button-bar="false" alt-input-formats="vm.altInputFormats" />' +
'<span class="input-group-btn">' +
'<button type="button" class="btn btn-default" ng-click="vm.showDatePicker()"><i class="glyphicon glyphicon-calendar"></i></button>' +
'</span>' +
'</div>' +
'</div>';
return{
controller: controller,
controllerAs: 'vm',
bindToController: true,
template: template,
restrict: 'EA',
scope :true,
require:'ngModel',
link: function( scope, element, attrs, ngModel ){
// Bring in changes from outside:
scope.$watch( 'ngModel', function(){
if( ngModel ) {
scope.$eval( attrs.ngModel + ' = ngModel' );
}
} );
// Send out changes from inside:
scope.$watch( attrs.ngModel, function( val ){
if( val ) {
scope.ngModel = val;
}
} );
if( attrs.readonly === 'true' ) {
scope.readonly = true;
}
}
};
“严格使用”;
角度.模块('frontendApp')
.指令('inputDate',函数(){
变量控制器=函数(){
var vm=这个;
函数init(){
vm.formats=['dd.MMMM-yyyy','yyyy/MM/dd','dd.MM.yyyy','shortDate'];
vm.format=vm.formats[0];
vm.altInputFormats=['M!/d!/yyyy'];
vm.dateOptions={
datepickerMode:'天',
年份:“yy”,
maxDate:新日期(),
minDate:新日期(1900年1月1日),
开始日期:1
};
vm.datepicker={
开放:假
};
};
init();
vm.showDatePicker=函数(){
vm.datepicker.opened=true;
};
};
变量模板=“”+
'' +
“{ngModel}日期:\'d.MMMM yyyy\'}”+
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'';
返回{
控制器:控制器,
controllerAs:'vm',
bindToController:对,
模板:模板,
限制:“EA”,
范围:正确,
要求:'ngModel',
链接:功能(范围、元素、属性、模型){
//从外部引入更改:
范围.$watch('ngModel',function(){
if(ngModel){
范围.$eval(attrs.ngModel+'=ngModel');
}
} );
//从内部发送更改:
范围$watch(attrs.ngModel,function(val){
if(val){
scope.ngModel=val;
}
} );
如果(attrs.readonly==='true'){
scope.readonly=true;
}
}
};
})
html部分是:
<input-date ng-model="form.flight.date"></input-date>
问题:如果弹出窗口出现,则scope.ngModel已从attrs.ngModel正确初始化。我在watcher中有一个日志,它告诉我监视attrs.ngModel效果很好,但是监视“ngModel”或scope.ngModel只在我使用日期选择器之前有效。只要不触发日期选择器,它就可以正常工作。
我刚刚发现如果我记得
“ng开关默认值”。将其替换为ng show/ng hide可使指令完全按预期工作
有人能解释为什么吗?你看到的行为绝对正确。当您使用结构指令,如
ng if
、ng switch
、ng repeat
等时,它会创建一个新范围并复制父范围的所有属性。您的模型是一个基本体(字符串),因此它将完全复制到新范围,并在此范围内进行更改,而不会传播到父范围
您可以做的是:
ng模型
,我个人觉得这里非常尴尬bindToController
和scope:true
的隔离作用域,因此只需使用watcher将模型绑定到控制器而不是跟踪模型:
return {
bindToController: true,
scope: {
ngModel: '='
},
...
因此,理想情况下,您甚至不需要在模板中使用链接函数而不是
'<div readonly name="readonlyText">{{ngModel | date : \'d.MMMM yyyy\'}}</div>'
“{ngModel}日期:\'d.MMMM yyyy\'}”
使用
“{vm.ngModel}日期:\'d.MMMM yyyy\'}”
为什么
ng hide
仍然有效?它不会创建新的范围。谢谢,第二种方法非常有效,并且很好地缩小了我的链接功能:)
'<div readonly name="readonlyText">{{vm.ngModel | date : \'d.MMMM yyyy\'}}</div>'