使用2个控制器管理工厂JSON $ http数据

时间:2016-05-10 00:33:58

标签: javascript angularjs

我试图获得factory JSON响应,将其保存在变量中,以便准备从2个不同的controllers调用。

下面我将使用以下代码粘贴代码:

storyFactory.js

var story = angular.module('story.services', []);

story.factory('storyAudio', [ '$http', function ($http) {

  var json = {};

  function getJSON(story_id, callback) {  
    $http({
      url: 'https://api.domain.co/get/' + story_id,
      method: "GET"
    }).success(function (data) {
      json = data;
      callback(data);        
    });
  };

  return {  
    getSubaudios: function(story_id, callback) {
      getJSON(story_id, function(result) {
        callback(result);
      });
    },
    getTopbar: function(callback) {
      callback(json);
    }
  };
}]);

StoryCtrl.js

var storyCtrl = angular.module('story', ['story.services']);

storyCtrl.controller('storyCtrl', [ 'CONFIG', '$stateParams', 'storyAudio', function(CONFIG, $stateParams, storyAudio) {

  var data = this;
  data.story = {};

  storyAudio.getSubvideos($stateParams.story_id, function(response) {
    data.story = response;
  });

}]);

TopbarCtrl.js

var topbarCtrl = angular.module('topbar', ['story.services']);

topbarCtrl.controller('topbarCtrl', [ 'CONFIG', '$stateParams', 'storyAudio', function(CONFIG, $stateParams, storyAudio) {
  var data2 = this;
  data2.story = {};

  storyAudio.getTopbar(function(response) {
    data2.story = response;
  });    
}]);

问题出在我的TopbarCtrl响应中,当我在HTML中调用它时,我收到一个空的data2.story。

原因是因为它没有$http响应的回调,所以它打印var json的实际状态,即空对象。

如果变量有内容,我怎么能加载第二个控制器?

感谢您的建议。

3 个答案:

答案 0 :(得分:3)

我认为在这种情况下你能做的最好的事情是通过getSubaudios加载数据,并提供对其他控制器使用的数据的引用。像这样......

story.factory('storyAudio', function($http) {
    var factory = {
        story: {}
    };

    factory.getSubaudios = function(story_id) {
        return $http.get('https://api.domain.co/get/' + story_id).then(function(response) {
            return angular.extend(factory.story, response.data);
        });
    };

    return factory;
})

使用angular.extend()而不是直接为工厂的story属性赋值可以维护在加载数据之前可能建立的任何引用。

然后您可以通过

加载数据
storyCtrl.controller('storyCtrl', function(storyAudio) {
    var data = this;
    storyAudio.getSubaudios($stateParams.story_id).then(function(story) {
        data.story = story;
    });
})

并通过控制器中的引用直接引用story数据

topbarCtrl.controller('topbarCtrl', function(storyAudio) {
    this.story = storyAudio.story;
})

答案 1 :(得分:1)

我认为我理解正确,但如果没有,请告诉我。

我看到了两个问题。首先是你的StoryCtrl.js文件中有一个拼写错误。您正在调用“storyAudio.getSubvideos”,但该函数在您的工厂中称为“getSubaudios”。

即使修正了错字,问题仍然可能在技术上发生。这一切都取决于承诺从第一次通话返回的速度。不幸的是,promises是异步的,因此无法保证在第二个控制器尝试获取之前设置“json”变量。

为了解决这个问题,您需要确保在尝试访问服务上的“json”变量之前完成第一个调用。可能有几种不同的方法可以做到这一点,但我想到的一种方法是实际返回并将承诺存储在服务中,如此......

  var dataPromise;
  function getSubaudios(story_id){
        if(!dataPromise){
          dataPromise = $http({
            url: 'https://api.domain.co/get/' + story_id,
            method: "GET"
          });
        }
        return dataPromise;
  }

  return {  
    getSubaudios: getSubAudios
  };

然后在您的控制器中,您可以调用该服务并使用.then在数据返回时从数据中获取数据...

storyAudio.getSubaudios($stateParams.story_id).then(function(response){
   data.story = response; //or data2.story = response;
});

这是一个plunkr示例。我已经使用$ q库来模拟从$ http请求返回的promise,但它应该说明这个想法。

答案 2 :(得分:1)

与菲尔的答案相似。 (角度扩展或角度复制使两个控制器中的引用保持相同。如果您不想在两个控制器中放置观察者以跟踪值是否发生变化。)这里有几种方法: Share data between AngularJS controllers

您还可以将要返回的对象直接绑定到update-function。这样参考文献保持不变。

storyServices.factory('storyAudio', ['$http', function($http) {
  return {
    data: { json: '' },
    getSubaudios: function(story_id) {
      $http.get('http://jsonplaceholder.typicode.com/posts/' + story_id)
        .then(function(response) {
          this.data.json = response.data.body;
        }.bind(this));
    }
  };
}]);

var storyCtrl = angular.module('story').controller('storyCtrl', ['$scope', 'storyAudio', function($scope, storyAudio) {
    $scope.data = storyAudio.data;
    storyAudio.getSubaudios(2);
}]);

var topbarCtrl = angular.module('story').controller('topbarCtrl', ['$scope', 'storyAudio', function($scope, storyAudio) {
    $scope.data2 = storyAudio.data;
}]);

在这里插入:http://plnkr.co/edit/auTd6bmPBRCVwI3IwKQJ?p=preview 我添加了一些范围来说明会发生什么。

旁注:

我认为直接命名你的非控制者" storyCtrl"是不诚实的。然后为它分配一个自己的控制器:

var storyCtrl = angular.module(...); // Nooo, this is not a controller.
storyCtrl.controller(...);   // This is a controller! Aaaah!

另一个旁注:

.success()是旧的做事方式。立即更改为.then(successCallback)!我敢说它是承诺的标准惯例。 https://docs.angularjs.org/api/ng/service/$http#deprecation-notice