javascript $watch 不能处理来自其他控制器的变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16883446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
$watch not working on variable from other controller?
提问by Foo Stack
I have one controller which displays a checklist, and stores the selection in an array.
我有一个控制器,它显示一个清单,并将选择存储在一个数组中。
My other controller runs an $http.get
on the array from the first controller.
我的另一个控制器$http.get
在第一个控制器的阵列上运行。
How do I set a $watch
so that whenever the array changes, a new HTTP GET request is sent?
如何设置 a$watch
以便每当数组更改时,都会发送新的 HTTP GET 请求?
My attempt: http://plnkr.co/edit/EaCbnKrBQdEe4Nhppdfa
我的尝试:http: //plnkr.co/edit/EaCbnKrBQdEe4Nhppdfa
// See plnkr for other controller + FooSelection factory + view
function SimpleQueryResCtrl($scope, $http, FooSelection) {
$scope.foo_list_selection = FooSelection;
$scope.$watch('foo_list_selection', function (newValue, oldValue) {
if (newValue !== oldValue)
$http.get('/api/' + $scope.foo_list_selection).success(function (largeLoad) {
$scope.myData = largeLoad;
});
});
}
SimpleQueryResCtrl.$inject = ['$scope', '$http', 'FooSelection'];
回答by Dan
By default, a $watch
checks for changes to a reference, not for equality. Since objects and arrays still have the same reference when modified, the watch is not triggered. There are at least two options to get it working.
默认情况下, a$watch
检查引用的更改,而不是相等。由于对象和数组在修改时仍然具有相同的引用,因此不会触发监视。至少有两个选项可以让它工作。
If the only changes you want to be notified of modify the size of the array (adding or removing elements vs. changing the content of an element), you can set the watch on the length property of the array instead like:
如果您想要通知的唯一更改是修改数组的大小(添加或删除元素与更改元素的内容),您可以在数组的 length 属性上设置监视,而不是像:
$scope.$watch('foo_list_selection.length', function (newValue, oldValue) {
// ...
Otherwise, you can use the optional $watch
argument objectEquality
, which expects a boolean. This does an equality check rather than a reference check.
否则,您可以使用可选$watch
参数objectEquality
,它需要一个布尔值。这会进行相等性检查而不是引用检查。
$scope.$watch('foo_list_selection', function (newValue, oldValue) {
if (newValue !== oldValue)
$http.get('/api/' + $scope.foo_list_selection).success(function (largeLoad) {
$scope.myData = largeLoad;
});
}, true); // <- put `true` here
This is not the default behavior because it performs a more costly deep check of all the elements so only use when necessary.
这不是默认行为,因为它对所有元素执行成本更高的深度检查,因此仅在必要时使用。
回答by rGil
Moving some of that logic into the factory, then sending it out to all controllers with a $rootScope.$broadcast
will get your information to the correct places.
将一些逻辑移入工厂,然后将其发送给所有控制器,$rootScope.$broadcast
并将您的信息发送到正确的位置。
I moved the array creation into the factory, then used the $broadcast from there:
我将数组创建移到了工厂中,然后从那里使用了 $broadcast:
myApp.factory('FooSelection', function ($rootScope) {
var tempArr = [];
var fixArray = function(item){
if (tempArr.indexOf(item) === -1){
tempArr.push(item);
} else {
tempArr.splice(tempArr.lastIndexOf(item), 1);
}
$rootScope.$broadcast('newArray', tempArr);
}
return {fixArray: fixArray}
})
Using $scope.$on
in the controllers receives the new data when it changes:
$scope.$on
在控制器中使用时会在新数据发生变化时接收新数据:
function SimpleQueryResCtrl($scope, $http, FooSelection) {
$scope.foo_list_selection = FooSelection;
$scope.$on('newArray', function(evt, message){
console.log(message) // and you can put your $get method here
})
}
回答by David Riccitelli
In such cases, I recommend using a service for data manipulation and messages to keep the controllers and UI in sync.
在这种情况下,我建议使用数据操作和消息服务来保持控制器和 UI 同步。
Take a look here: AngularJS multiple uses of Controller and rootScope