【问题标题】:$watch not working on variable from other controller?$watch 不能处理来自其他控制器的变量?
【发布时间】:2013-05-28 19:39:42
【问题描述】:

我有一个控制器,它显示一个清单,并将选择存储在一个数组中。

我的另一个控制器从第一个控制器的阵列上运行$http.get

如何设置$watch,以便每当数组更改时,都会发送一个新的 HTTP GET 请求?

我的尝试: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'];

【问题讨论】:

  • 我认为您的代码是正确的,您是否遇到错误?您还可以检查是否 newValue !== oldValue 以确保您的请求仅在 'foo_list_selection' 真正改变时才被触发。
  • 好的,我相信这是我能做的最简单的可运行示例:plnkr。您应该在控制台中看到发出了 HTTP 请求,但此示例中没有发出任何请求。
  • 我修复了你的 plunker 中的一些错误,它似乎工作正常:plnkr.co/edit/nnRw4Pu5x9YQyyqWPc4h?p=preview
  • 它对我有用,每次我在输入中输入一些内容时,如果被触发到 /api/ + foo_list_selection,就会收到一个 get 请求。
  • 谢谢,您的示例确实有效。不幸的是,当我从 input 标签切换到我的复选框标签时,它失败了。

标签: javascript angularjs angularjs-scope angularjs-service angularjs-controller


【解决方案1】:

默认情况下,$watch 检查对引用的更改,而不是相等性。由于对象和数组在修改时仍然具有相同的引用,因此不会触发监视。至少有两个选项可以让它工作。

如果您想要通知的唯一更改是修改数组的大小(添加或删除元素与更改元素的内容),您可以在数组的长度属性上设置监视,而不是像:

$scope.$watch('foo_list_selection.length', function (newValue, oldValue) {
// ...

否则,您可以使用可选的$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

这不是默认行为,因为它对所有元素执行更昂贵的深度检查,因此仅在必要时使用。

【讨论】:

  • 谢谢,相当肯定这就是我正在寻找的答案。虽然无法让它与这个例子一起工作,也许你可以帮忙? - 我用$scope.$watch 条件包裹了行13-40 of main.js,在注入(并带入$scope)的变量上。它不起作用:(。这是来自ng-grid paging example BTW。
  • 这些行似乎是函数定义,所以我认为它们可能不是您真正想要的手表主体。也许你可以发布你的新代码(带有手表包装)和一个关于你想要做什么的新问题。
【解决方案2】:

将其中的一些逻辑移入工厂,然后将其发送到带有$rootScope.$broadcast 的所有控制器,将您的信息发送到正确的位置。

我将数组创建移到工厂中,然后从那里使用 $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}
})

在控制器中使用$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
})
}

Here's the plunk

【讨论】:

    【解决方案3】:

    在这种情况下,我建议使用数据操作和消息服务来保持控制器和 UI 同步。

    看这里:AngularJS multiple uses of Controller and rootScope

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多