材料升级后AngularJS自定义指令双向绑定中断
Posted
技术标签:
【中文标题】材料升级后AngularJS自定义指令双向绑定中断【英文标题】:AngularJS custom directive bidirectional binding broken after material upgrade 【发布时间】:2017-08-01 07:47:38 【问题描述】:我写了一个在 Angular 1.6.1 和 material 1.1.1 下工作的小指令。 这是一个简单的锁定/解锁按钮图标。
我不得不将材料更新到 1.1.3(用于日期选择器),但此后该指令不再起作用。
我不明白为什么材料更新会这样做...... 下面的 plunker 可以工作,但是如果你将材料版本更改为 1.1.2,它就会停止工作。
http://plnkr.co/edit/ZamxN3WTXaOl5cTv4aWI?p=info
index.html:
<html lang="en" >
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.3/angular-material.css">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-aria.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.1/angular-material.js"></script>
<!-- <script src="//cdnjs.cloudflare.com/ajax/libs/angular-material/1.1.1/angular-material.js"></script> -->
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="controller as ctrl">
<ju-lock ng-model="ctrl.lock"></ju-lock>|ctrl.lock|
</body>
</html>
script.js:
angular
.module('app', ['ngMaterial'])
.directive('juLock', function()
return
restrict: 'E',
scope:
bindModel: '=ngModel'
,
template:
'<md-button class="md-icon-button">'+
'<md-icon class="material-icons">lock_open</md-icon>'+
'</md-button>|bindModel',
link: function(scope, element, attributes)
element.on('click', function (ev)
scope.bindModel = !scope.bindModel;
);
scope.$watch('bindModel', function()
angular.element(element[0].querySelector('.material-icons')).text(scope.bindModel ? 'lock' : 'lock_open');
);
;
)
.controller('controller', function()
var vm = this;
vm.lock=true;
);
在询问堆栈社区之前,我已经尽可能多地进行了调查,是否有人对此有所了解?
【问题讨论】:
避免在自定义指令中使用ng-model
作为属性。如果这样做,请不要对其使用隔离范围双向绑定。使用该属性实例化的ngModelController API。
【参考方案1】:
避免在自定义指令中使用ng-model
作为属性。如果这样做,请不要使用隔离范围双向绑定。使用该属性实例化的ngModelController API。
主要问题是jqLite click handler需要用scope().$apply()通知AngularJS框架范围的变化:
element.on('click', function (ev)
scope.bindModel = !scope.bindModel;
//USE $apply
scope.$apply();
);
Angular 通过提供自己的事件处理循环来修改正常的 javascript 流程。这将 JavaScript 拆分为经典和 Angular 执行上下文。只有在 Angular 执行上下文中应用的操作才能受益于 Angular 数据绑定、异常处理、属性监视等……您使用 $apply() 从 JavaScript 进入 Angular 执行上下文。
请记住,在大多数地方(控制器、服务)
$apply
已经被处理事件的指令调用。 仅在实现自定义事件回调或使用第三方库回调时才需要显式调用$apply
。——AngularJS Developer Guide - Integration with the browser event loop
DEMO on PLNKR
也不是操纵 DOM 来更改锁定和解锁图标。它可以通过ng-show 和ng-hide 指令来完成:
app.directive('juLock', function()
return
restrict: 'E',
scope:
bindModel: '=myModel'
,
template:
'<md-button class="md-icon-button">'+
'<md-icon ng-show="bindModel" class="material-icons">lock</md-icon>'+
'<md-icon ng-hide="bindModel" class="material-icons">lock_open</md-icon>'+
'</md-button>|bindModel',
link: function(scope, element, attributes)
element.on('click', function (ev)
scope.bindModel = !scope.bindModel;
//USE $apply
scope.$apply();
);
/*
scope.$watch('bindModel', function()
angular.element(element[0].querySelector('.material-icons')).text(scope.bindModel ? 'lock' : 'lock_open');
);
*/
;
)
【讨论】:
@glorfindel 你不需要使用 Wayback 机器。图片已移至docs.angularjs.org/img/guide/concepts-runtime.png 感谢您发现这一点,我的机器人无法检测到此类情况。我的浏览器甚至无法加载code.angularjs.org/1.1.5/docs/img/guide/concepts-runtime.png,而且我自己从未做过角度项目。【参考方案2】:我不确定版本之间的确切问题,但请查看fiddle,此代码适用于两个版本。
关键是使用ng-click
,它来自angularJs,而不是依赖element.on()
,如果你注入jQuery
或者你不注入,它可能会有所不同。另外这种方式更具声明性
我所做的唯一更改是在您的指令中
.directive('juLock', function()
return
restrict: 'E',
scope:
bindModel: '=ngModel'
,
template:
'<md-button ng-click="bindModel = !bindModel" class="md-icon-button">'+
'<md-icon class="material-icons">lock_text</md-icon>'+
'</md-button>|bindModel',
link: function(scope, element, attributes)
scope.lock_text = '';
scope.$watch('bindModel', function()
scope.lock_text = scope.bindModel ? 'lock' : 'lock_open';
);
;
)
我还删除了您手表中的 dom 检查,并且我以 Angular 样式进行了更多操作
【讨论】:
以上是关于材料升级后AngularJS自定义指令双向绑定中断的主要内容,如果未能解决你的问题,请参考以下文章
玩转angularJs——通过自定义ng-model,不仅仅只是input可以有双向绑定