我偶然发现了一个我不了解或不知道如何解决问题的Angular问题。
我希望在控制器中有一个回调函数,一旦指令完成,指令就会调用它。该指令首先改变一些范围变量并运行回调。然后回调函数继续使用相同的范围变量执行某些操作。这可能看起来令人困惑,为什么我想要这个,但认为该指令是通用的并处理许多不同的情况,而回调是一个非常具体的功能。需要注意的是,我不能将此变量作为参数传递,因为其他代码也需要使用此范围变量。
现在解决问题了。我已经完成所有工作直到执行回调。似乎在回调中,变量尚未改变。但是,如果设置了超时(在我的示例中为一秒),则变量将被识别为已更改。为什么会有这种行为?即使在调用回调之前的指令中,它也显示变量实际上已更改。我已经创建了一个演示此问题的Codepen。它简单地切换了A' A'到' B'您会注意到,在控制台日志中,当变量在回调中打印时,它就是“旧”字样。在我等待之前的价值。
任何信息都会很棒,谢谢!
注意:我想到的一个想法是将范围变量的副本保存为指令中的局部变量,并将该局部变量作为参数发送到回调,因为回调是目前我唯一关心的函数知道变量的变化并对其起作用。
Codepen:http://codepen.io/anon/pen/KayaRW
HTML:
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-test="" button-label="myLabel" callback="cbFunc()">
</div>
</div>
JS:
angular
.module('myApp', [])
.controller('myCtrl', function($scope) {
$scope.myLabel = "A";
$scope.cbFunc = function() {
console.log("myLabel in callback: " + $scope.myLabel);
setTimeout(function() {
console.log("myLabel in callback, after 1 sec: " + $scope.myLabel);
console.log("");
}, 1000);
}
}).directive('ngTest', function() {
return {
scope: {
buttonLabel: '=',
callback: '&'
},
template: function(element, attrs) {
element.html("<button class=\"btn\" ng-click=\"changeLabel()\">Button Label: {{buttonLabel}}</button>");
},
link: function($scope, $element, $attrs) {
$scope.changeLabel = function() {
if ($scope.buttonLabel == "A") {
$scope.buttonLabel = "B";
} else {
$scope.buttonLabel = "A";
}
console.log("myLabel before callback: "+ $scope.buttonLabel);
$scope.callback();
}
}
}
});
答案 0 :(得分:1)
您有几个选择。我相信你的问题正在发生,因为该指令正在创建一个孤立的范围。 我还将指令更改为可读性元素:
1)不要使用回调,你的$ scope.myLabel已经双向约束。
2)您可以将超时设置为0,它似乎仍然有效。我使用了$ timout服务:
<div ng-app="myApp" ng-controller="myCtrl">
<ng-test button-label="myLabel" callback="cbFunc()"> </ng-test>
<p>
Here is the updated label in the timeout::::: {{updatedLabel}}
</p>
</div>
angular
.module('myApp', [])
.controller('myCtrl', function($scope, $timeout) {
$scope.myLabel = "A"; //inital value
$scope.cbFunc = function() {
$timeout(function() {
//$scope.myLabel is updated, $timeout is like an $apply but better
}, 0);
}
}).directive('ngTest', function() {
return {
restrict: 'E',
scope: {
buttonLabel: '=',
callback: '&'
},
template: function(element, attrs) {
element.html("<button class=\"btn\" ng-click=\"changeLabel()\">Button Label: {{buttonLabel}}</button>");
},
link: function($scope, $element, $attrs) {
$scope.changeLabel = function() {
if ($scope.buttonLabel == "A") {
$scope.buttonLabel = "B";
} else {
$scope.buttonLabel = "A";
}
$scope.callback();
}
}
}
});
3)您的回调可以接受参数,指令会将其传回去,您说这不是一个选项。
<div ng-app="myApp" ng-controller="myCtrl">
<ng-test button-label="myLabel" callback="cbFunc(data)"> </ng-test>
<p>
Here is the updated label in the timeout::::: {{updatedLabel}}
</p>
</div>
angular
.module('myApp', [])
.controller('myCtrl', function($scope,$timeout) {
$scope.myLabel = 'A';
$scope.cbFunc = function(data){
$scope.updatedLabel = data;
}
}).directive('ngTest', function() {
return {
restrict: 'E',
scope: {
buttonLabel: '=',
callback: '&'
},
template: function(element, attrs) {
element.html("<button class=\"btn\" ng-click=\"changeLabel()\">Button Label: {{buttonLabel}}</button>");
},
link: function($scope, $element, $attrs) {
$scope.changeLabel = function() {
if ($scope.buttonLabel == "A") {
$scope.buttonLabel = "B";
} else {
$scope.buttonLabel = "A";
}
$scope.callback({data: $scope.buttonLabel});
}
}
}
});
4)$每次更新时都会释放对象,控制器可以监听它。在您的指令中而不是调用回调,请调用
$scope.$emit('sudoCallback', $scope.buttonLabel);
并在您的控制器中而不是您拥有的回调函数
$scope.$on('sudoCallback', function(event, data) {$scope.updatedLabel = data });
我不喜欢这个选项,因为范围层次结构会导致问题
5)在$ scope.myLabel的控制器中使用$ watch并完全摆脱回调。
$scope.$watch('myLabel', function(newVal){
$scope.updatedLabel = newVal;
});
我不喜欢添加一堆手表,但它有效。
github上还有一个非常酷的库,它充当消息中心,因此您不需要关心范围层次结构,只需订阅和发布即可。 GitHub Angular Message Bus