我有嵌套的指令应该像<select>
元素一样工作。当点击我的“select”元素中的一个项目时,它应该触发一个事件,该事件应该由父指令拦截并采取行动。但是,我遇到了一些奇怪的行为,其中双向数据绑定无法正确更新。
在关联的 Plunk 中,当您点击Assign "bar" as a value
时,第一次点击无效。它只适用于第二次点击。
为什么?
以下是相关代码:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = {
value: 'foo'
}
$scope.processForm = function() {
console.log('processForm function on controller executed.')
$scope.newValue = $scope.name.value
}
});
app.directive('aaButtonGroup',
function($rootScope) {
return {
template: '<div ng-transclude></div>',
restrict: 'E',
transclude: true,
scope: {
aaChange: '&'
},
link: function (scope, element, attrs) {
$rootScope.$on('xyzClick', function() {
console.log('aaChange expression on aaButtonGroup executed.')
scope.aaChange()
})
}
}
}
)
app.directive('aaButtonGroupItem',
function($rootScope) {
return {
template: '<a href="#" ng-click="processClick(\'bar\')">Assign "bar" as a value</a>',
restrict: 'E',
scope: {
ngModel: '=',
},
replace: true,
link: function(scope) {
scope.processClick = function(key) {
console.log('aaButtonGroupItem processClick function executed.')
scope.ngModel = key
$rootScope.$broadcast('xyzClick')
}
}
}
}
)
和HTML
<aa-button-group aa-change="processForm()">
<aa-button-group-item
ng-model="name.value"></aa-button-group-item>
</aa-button-group>
<pre>Value: {{newValue || 'Undefined'}}</pre>
这是 Plunk 。
答案 0 :(得分:2)
首先,有两种解决方法:
$ setViewValue fix
替换:scope.ngModel = key;
使用:ngModelController.$setViewValue(key);
(并添加require: '^ngModel',
和ngModelController
作为链接的第4个参数),如下所示:
require: '^ngModel',
replace: true,
link: function(scope,element,attrs,ngModelController) {
scope.processClick = function(key) {
ngModelController.$setViewValue(key);
$rootScope.$broadcast('xyzClick')
}
$ watch fix
不要基于事件触发将newValue
绑定到name.value
,而是让Angular通过监视来处理它:
$ scope.processForm = function(){ $ scope。$ watch('name.value',function(){ $ scope.newValue = $ scope.name.value; }) }
基础问题
时序。执行此行scope.ngModel = key;
时,更改不会立即传播到实际的ngModel
。该模型将在下一个$digest
周期更新。
您可以通过添加以下日志来确认:
scope.ngModel = key;
console.log("key ",key);
console.log("view value ",ngModelController.$viewValue);
console.log("model value ",ngModelController.$modelValue);
当您单击按钮时,将显示:
键栏
查看价值foo
模型值foo
立即使用$setViewValue
更新ngModel
,因此您没有$digest
延迟。所以:
ngModelController.$setViewValue(key);
结果:
键栏
查看值栏
模型价值栏
另一个解决方案是在$timeout
放置newValue
,以便在摘要周期结束后发生:{/ p>
$scope.processForm = function() {
$timeout( function() {
$scope.newValue = $scope.name.value;
},0);
}
但我认为使用$watch
或直接设置模型是更清晰的解决方案。