取决于相同数据的两个控制器异步返回

时间:2015-08-17 01:38:05

标签: angularjs angularjs-service

有一个应用程序允许用户创建或加入房间。因此RoomsListController显示会议室RoomDetailsController,其中显示特定会议室内活动的内容和控制。原因是RoomService提供getRooms()(异步)方法。

现在什么是Angular方法让两个控制器等待RoomService.getRooms()返回的相同数据?

详细说明:

  • 应用程序中有身份验证,房间列表取决于userId。因此,在应用程序启动时调用RoomService.getRooms()不是一个选项
  • RoomDetailsController并不总是要求提供房间清单。每当通过$stateParams提供的房间存在且处于活动状态时,它就会被简单显示。如果没有,有一些逻辑可以引导用户到另一个房间(这里需要房间列表)或者显示一条消息,说明没有房间可用,也许是时候创建房间了。
  • 让我们假设getRooms()对于服务器来说是一项繁重的操作,当客户端上的相同数据可以重复使用时,它不希望得到它两次。
  • 希望逻辑不依赖于首先执行哪个控制器功能,因为这可能会受到模板中布局更新的影响

2 个答案:

答案 0 :(得分:2)

看看route resolve promises

在路由解析之前,您将调用异步方法

// in your config
$routeProvider.when('/your-route', {
  resolve: {
    roomData: function(RoomService) {
      return RoomService.getRooms();
    }
  }
}

// RoomsListController
function(roomData) {
  // do something with roomData
}

// RoomDetailsController
function(roomData) {
  // do something with roomData
}

这样,就控制器而言,在路由加载之前数据已经存在。

您已经触及其中一个关键问题是应用程序......也就是说,为应用程序可以使用它的方式组成的数据创建单一的事实来源。

有很多模式可以解决这个问题,但我建议您将路线解析承诺作为一个起点,并从那里开始分支。它会变得非常复杂。

答案 1 :(得分:1)

另一种方法可能是修改服务中的RoomService.getRooms()函数,以在第一次调用函数时声明并存储本地promise,同时等待服务器的结果。如果再次调用该函数,您将立即返回相同的承诺。从服务器返回结果后,您可以解析存储的承诺并清除它,因此下次调用它时,将会发出新的请求。

当然,这里有足够的空间来定制。例如,如果您知道来自服务器的数据永远不会改变,那么您根本不需要清除承诺。每次要求房间时都要退货。

以下是一个示例实现:



var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope, RoomService) {
  $scope.name = 'World';

  $scope.fetchingStatus = function() {
    return RoomService.serverRequests ? 'Fetching... Server Requests: ' + RoomService.serverRequests : '';
  };

  $scope.getRooms = function() {
    console.log('asking for rooms')
    RoomService.getRooms().then(function(rooms) {
      console.log('rooms returned: ', rooms);
      $scope.rooms = rooms;
    });
  };
});

function RoomService($q, $timeout) {
  this.$q = $q;
  this.$timeout = $timeout;
  this.getRoomsPromise = null;
  this.serverRequests = 0;
}

RoomService.prototype.getRooms = function() {
  if (!this.getRoomsPromise) {
    this.getRoomsPromise = this.$q.defer();
    this.getRoomsFromServer();
  }
  return this.getRoomsPromise.promise;
};

RoomService.prototype.getRoomsFromServer = function() {
  var rooms = [];
  for (var i = 1; i <= 10; i++) {
    rooms.push({
      id: i,
      name: 'Room ' + i
    });
  }
  console.log('fetching data from server...');
  this.serverRequests++;
  this.$timeout(function() {
    this.serverRequests--;
    this.getRoomsPromise.resolve(rooms);
    this.getRoomsPromise = null;
    console.log('got data from server...')
  }.bind(this), 1500);
}

app.service('RoomService', RoomService);
&#13;
.fetching {
  background-color: red;
  color: white;
  padding: 2px 10px;
  display: inline-block;
  margin-left: 50px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
  <p>
    <button ng-click="getRooms()">Get Rooms</button>
    <span class="fetching" ng-show="fetchingStatus()">{{fetchingStatus()}}</span>
  </p>
  <ul>
    <li ng-repeat="room in rooms track by room.id">{{room.name}}</li>
  </ul>
</div>
&#13;
&#13;
&#13;