我无法在我的控制器中访问 $rootScope

I am unable to access $rootScope in my controller

我在 $rootScope 中有一些参数,如下所示:

myApp.factory('itemService', function($http) {
    return $http.get('/items');
});

myApp.run(function($rootScope, itemService) {
    itemService.success(function(response) {
        $rootScope.items = response;
    });
});

myApp.controller('displayCtrl', function($rootScope, $scope) {
    $scope.items = $rootScope.items;
});

当我 运行 上面的代码时,我从 firebug 得到这个错误 TypeError: $rootScope.items is undefined。我真的不知道发生了什么。

这里有一点补充。 items 是一个包含如下对象列表的数组:

items = [
  {'name': 'spoon', 'price': 200},
  {'name': 'table', 'price': 400},
  {'name': 'shoe', 'price': 250}
];

我希望 items 在我的应用程序中始终可用,这样我就可以在项目列表(项目)中显示每个项目,而无需向服务器发出另一个请求。我打算通过每次需要显示一个项目时使用 $scope.item = items[$routeParams.id] 简单地显示一个项目来实现这一点。 我期待使用附加到 ng-click 的函数或正常的 #/route/:param 机制来实现这一点。 谢谢

您 运行 在 运行 块的异步方法:

 itemService.success(function(response){
    $rootScope.items = response;
});

但是初始化还在继续,所以您可能在 itemService 成功之前访问了 $rootScope.items(或者它失败了,而您没有预料到这种情况)。我建议你这样做(如果你想遵循 $rootScope 约定......顺便说一句,这很糟糕):

 $rootScope.items = [];
 itemService.success(function(response){
    $rootScope.items = response;
 });

您正在异步进程的回调中设置 items,因此您试图在 $rootScope 实际设置之前访问 items

如果您尝试在加载控制器时初始化 items,那么还有其他方法可以做到这一点,例如使用路由的解析块或手动调用 $http.get控制器加载时的工厂。

TypeError: $object.property is undefined 通常是因为在设置特定对象(或其 属性)之前发出了对对象引用的请求。 $http 请求本质上是异步的,因此其他进程不会被阻塞。很明显,尝试使请求同步可能会给连接速度非常慢的人带来重大问题。

除此之外,污染 $rootScope 通常不是一个好主意。您可以在下面的 link 上找到有关全局变量的主题,以便您调查为什么 $rootScope 不是一个好地方。

说了这么多,在我看来您不想发出多个请求来检索相同的数据。如果是这样,您可以为 $http.get 方法使用缓存选项。

例如:

myApp.factory('itemService', function($http, $q) {
  return {
    get: function() {
      return $http({
        url: 'items.json',
        cache: true //keep the result in memory 
      });
    }
  };
})

myApp.controller('aCtrl', function(itemService) {
  var self = this;

  itemService.get().success(function(data) {
    self.items = data;
  });
});

myApp.controller('bCtrl', function(itemService) {
  var self = this;

  itemService.get().success(function(data) {
    self.items = data;
  });
});

这将确保信息被请求一次并放入缓存中。可以在不同的地方访问数据。

  <div ng-controller="aCtrl as a">
    {{a.items}}
  </div>
  <div ng-controller="bCtrl as b">
    {{b.items}}
  </div>

这给我留下了另一个 'good' 实践:controllerAs 语法的用法。它提供了一种在 AngularJS 中使用命名空间的方法。

当然,这些只是提示,您应该始终考虑这些要求!

最后,我想出了一个解决办法。我意识到问题是 $rootScope.itemsdisplayCtrl 加载的同时可用。但是当我的 html 页面加载时,$rootScope.items 在我的视图中可用。 所以我只是简单地将item id作为参数传递,然后使用$routeParams获取它如下

myApp.controller('displayCtrl', function($routeParams, $scope) {
    $scope.item_id = $routeParams.id; //given that the route looks like '/item/:id'
}); 

然后在我的HTML文件中我所做的

<div ng-bind="items[item_id].name"></div>
<div ng-bind="items[item_id].price"></div>

这实际解决了我的问题。