【问题标题】:How to instantiate variable before the controllers are loaded如何在加载控制器之前实例化变量
【发布时间】:2015-05-08 08:18:16
【问题描述】:

我有一个简单的 AngularJS 应用程序。我现在正在尝试在其中实现 L10n* 机制。为此,我有一个服务,它加载一个字符串文件并返回一个键值数组。这些值稍后会放入视图和控制器中。

为了使事情简单明了,我将返回数组分配给 $rootScope 以便每个控制器/视图都可以访问相同的列表。 我是从 angular.module(...).run() 函数

这就是问题的开始——一些控制器可以访问 $rootScope 对象,而其他一些则不能(并返回未定义)。我怀疑这是因为在加载前几个控制器之前没有及时解决承诺。

问题是 - 如何让控制器等待资源加载?

辅助问题 - 为什么 GenericListController 可以使用 $scope.localisation 而 ListController 不能?

服务声明

app.factory("StringsTranslationService", function($http) {

    var getData = function(locale) {

        return $http({method:"GET", url:'public/resources/strings_'+locale+'.txt'}).then(function(result){
            return result.data[0];
        });
    };
    return { getData: getData };
});

将数据从服务加载到 app.js

中的 $rootScope
app.run(function($rootScope,StringsTranslationService) {
    var myDataPromise = StringsTranslationService.getData('en');
    myDataPromise.then(function(result) {
        $rootScope.localisation=result;
    });
});

最后尝试在controller.js中使用:

var app=angular.module('myApp');

app.controller('ListController', function ($scope, $controller){
    console.log($scope.localisation["_NAME_"]);
    angular.extend(this, $controller('GenericListController', {$scope: $scope}));
});

最有趣的事实是,GenericListController 也使用了相同的 $scope.localisation 数组并且它没有问题!

加载顺序为:

  1. app.js
  2. service.js
  3. genericController.js
  4. controller.js

【问题讨论】:

  • 您是否考虑过将值数组存储在工厂对象中并将依赖项注入控制器而不是将数据分配给路由范围?
  • 是的,托比,我有,但这对我来说不是一个非常有效的解决方案 - 请参阅下面我对 nitin 回答的评论。简而言之 - 1)我不能 b/c 我的视图有时没有控制器,但我在那里使用模型变量。 2)我有一堆控制器,我不想为每个控制器添加额外的代码只是为了支持异步轮询。我需要从 $scope.localisation 以相同的方式加载一次数组并始终可用

标签: angularjs angularjs-scope


【解决方案1】:

您应该直接从服务中读取,而不是将您的结果复制到 $rootScope。

为什么? Yr $rootScope 存在于整个应用程序生命周期中,它位于所有控制器范围的上方,因此最好保持最轻。

代码:

app.factory("StringsTranslationService", function($http,$q) {

  var StringsTranslationService={};
  var data='';
  var dataReady=false;

  StringsTranslationService.getData = function (locale) {

    var deferred= $q.defer();
    $http({
      method:"GET",
      url:'public/resources/strings_'+locale+'.txt'
    })
    .success(function(result){
      deferred.resolve(result.data[0]);
    })
    .error(function(error){
      deferred.reject(error);
    })
    return deferred.promise;

 };

 return StringsTranslationService;
});

更新你的 app.run

app.run(function(StringsTranslationService){

   //call service & read data
    StringsTranslationService.getData('en')
     .then(function(data){
          StringsTranslationService.data=data;
          StringsTranslationService.dataReady=true;

          //if you really want it add to rootScope
          //$rootScope.localisation=data;
      },
      function(error){
          //handle error here
      })  

});

在你的控制器内部检查数据是否准备好然后读取

app.controller('ListController', function ($scope, StringsTranslationService){

    if(StringsTranslationService.dataReady===false){
      $scope.loading=true;
    }
    else {
       $scope.loading=false;
       $scope.data=StringsTranslationService.data;
    }


});

这样,您只需执行一次调用即可获取数据,并且可以跨应用使用。

【讨论】:

  • 我已经考虑过这种方法,但它对我来说不是很可行,原因有两个 - 我有一卡车相互交织的控制器(需要更新每个) - 更重要的是 - 我的一些观点(index.html) html) 不要使用控制器 - 所以我需要那里可用的应用程序范围的变量。这不能更简单吗?还有 - 为什么不使用 $rootScope 更好(我从互联网上得到的印象)
  • 不幸的是,我没有找到解决问题的确切方法。基本上我需要告诉 Angular - 仅在完成负载控制器时才执行“此操作”。看起来那是不可能的。耻辱..无论如何,我最终实现了与上面提出的解决方案类似的解决方案 - 一个服务并将我的每个控制器包装到一个 then 指令(!)中。这产生了一个非常难看的代码。此外,每次都重新加载资源 - 超过 10 次连续读取同一文件。幸好我找到了 $http.get() 的 {cache: true} 选项。谢谢大家!
  • 顺便说一句,这不完全是我的问题/问题的答案,但我很感激付出的努力和时间。谢谢!
猜你喜欢
  • 2011-07-29
  • 1970-01-01
  • 2016-07-14
  • 2016-04-17
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多