【问题标题】:Traversing JSON data from Angular Factory从 Angular Factory 遍历 JSON 数据
【发布时间】:2013-11-05 19:59:20
【问题描述】:

我有一个角度控制器,它使用工厂从 JSON 文件返回响应。 当我尝试遍历返回的数据时,我在评论中看到以下错误。 但是,如果我在尖括号内的 HTML 内使用 realArticleData 对象,它会完美地横向。我认为这与工厂返回的承诺有关,但我不确定。

控制器片段:

function SpecialOrderItemsCtrl($scope, $location, articleDataService) {
    $scope.realArticleData = articleDataService.getArticles();
    //This throws TypeError: Cannot read property 'thdCustomer' of undefined
    $scope.custInfo = $scope.realArticleData.articles.thdCustomer;
}

HTML 片段:

<div ng-controller=SpecialOrderItemsCtrl>
<label>Raw Article JSON</label>
<p>{{realArticleData}}</p>
<label>Json transversed by one level</label>
<p>{{realArticleData.articles}}</p>
<label>THD CUstomer </label>
<p>{{realArticleData.articles.thdCustomer}}</p>
</div>

工厂:

function articleDataService($rootScope, $http) {
    articleDataService.data = {};
    articleDataService.getArticles = function() {
    $http.get('articleData.json')
        .success(function(data) {
            articleDataService.data.articles = data;
        });
        return articleDataService.data;
    };
    return articleDataService;
}
sendDesign.factory('articleDataService', articleDataService);

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    您正在处理承诺。因此,您需要异步处理它们。 如

    angular.module('plunker', []).controller('SpecialOrderItemsCtrl', ['$scope', 'articleDataService',  function($scope, articleDataService){
      // when promise is resolved, set the scope variable
      articleDataService.getArticles().then(function(articles){
          // store any data from json that you want on the scope for later access in your templates
          $scope.articles = articles;
      })
    }]).factory('articleDataService',['$http', '$q', function($http, $q){
      var data = null;
      return {
        getArticles: function() {
          var promise;
          if(data === null) {
            promise = $http.get('articleData.json').then(function(response){
              // cache the response
              data = response;
              return response;
            });
          } else {
            var deferred = $q.defer();
            // promise is immediately resolved with the cached data
            // this way both cached and async data can be handled consistently
            promise = deferred.promise;
          }
          return promise;
        }
      } ;
    }]);
    

    Plunkr 链接:http://plnkr.co/edit/7Oas2T

    【讨论】:

    • plunker 的链接是plnkr.co/edit/7Oas2T,并且您在控制器中按范围存在语法错误。我添加了 ],现在我得到错误:Argument 'SpecialOrderItemsCtrl' is not a function, got string.
    • 语法错误已修复,我现在得到 Object # has no method 'getArticles'。
    • 是的,发现了我的问题,先在 plunkr 中修复它,然后再把它带到这里
    • $http 服务的名称有错别字,并且范围内的预期数据与控制器提供的数据之间存在脱节。我的答案中的 Plunkr 现在应该可以工作了
    【解决方案2】:

    将您的服务更改为:

    articleDataService.getArticles = function() {
        $http.get('articleData.json').then(function(result) {
            return result.data
        });
    }
    

    在你的控制器中:

    articleDataService.getArticles().then(function(data) {
        $scope.realArticleData = data;
        $scope.custInfo = $scope.realArticleData.articles.thdCustomer;
    });
    

    您需要按照承诺模式返回控制器,否则您无需等待呼叫完成,您将收到undefined

    【讨论】:

    • 我相信缓存 http 响应是原始代码的意图之一。使用您的方法,每次调用 getArticles 都会发出一个 http 请求(可能是也可能不是 304d)
    • 仍然难以实施您的解决方案。一旦我弄清楚就会接受。
    • 创建一个 plunkr 来展示您的问题。可能导致问题的一件事是从控制器中的承诺范围内更改范围。我更新了包含在 $scope.apply 中的代码。看看是否有效
    【解决方案3】:

    要记住的关键点是,promise 不会返回值,它们会在值到达时或在值到达时执行一些操作

    此答案基于@VladimirGurovich 和@tymeJV 的答案。

    这是一个简单的工厂:

    var app = angular.module('myApp', []);    
    
    app.factory('Names', ['$http', function($http) {
      return {
        url: 'names.json',
        fetch: function() {
          return $http.get(this.url, {cache: true}).then(function(json) {
            return json.data;
          });
        }
      };
    }]);
    

    Names 工厂本身返回一个对象。 fetch 方法从 $http.get 返回承诺链。这使用.then() 而不是.success(),因此可以链接结果。工厂可以直接返回$http 承诺,但给操作命名对我来说似乎更清楚。

    @VladimirGurovich 的答案是手动处理缓存,但 Angular 可以为我们做到这一点,只需将类似 {config: true} 的配置对象与 URL 一起发送到 $http.get

    这是一个简单的小控制器,它依赖于来自 Names 工厂的数据:

    app.controller('MainCtrl', ["$scope", "Names", function($scope, Names) {
        Names.fetch().then(function(data) {
            $scope.names = data.names;
        });
    }]);
    

    Names.fetch() 承诺完成后,$scope.names 将填充返回的数据。

    这是基于此的 Plunker:http://plnkr.co/edit/nMx1XL

    【讨论】:

      猜你喜欢
      • 2017-11-21
      • 2021-02-11
      • 2017-09-14
      • 2018-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      相关资源
      最近更新 更多