Angularjs服务来管理跨多个控制器的数据集

时间:2013-11-29 00:46:20

标签: angularjs

基本上我的应用程序的核心在于通过$ http请求从服务器检索的一组数据。一旦数据可供客户端使用(作为对象数组),我需要它用于多个视图,并且希望在它们之间保持它的状态,例如,如果它已被过滤,我希望只有过滤后的数据可用于其他观点。

目前我有一个检索数据的基本服务,然后在app范围的控制器中管理数据(数组)的状态(见下文)。这很好用,但是当我尝试在每个视图的控制器上维护数组长度,过滤状态,可见/隐藏对象时,它开始变得一团糟,因为我必须在应用程序范围的控制器中保持currentVenue等的跟踪。注意:我在每个视图中使用ng-repeat来显示和过滤数据(另一个原因我想让它在中心点过滤)。

显然这不是最佳选择。我假设我应该使用服务来维护场地对象的数组,因此它将包含当前场所,当前页面,负责过滤阵列等,并将其注入每个控制器。我的问题是,如何设置服务以具有此功能(包括在启动时从服务器加载数据;这将是一个良好的开端tbh),这样我就可以实现这一点,然后将结果绑定到范围。即:每个视图控制器中的$scope.venues = venues.getVenues$scope.current = venues.currentVenue

services.factory('venues', function ($http, $q) {
    var getVenues = function() {
        var delay = $q.defer();

        $http.get('/api/venues', {
            cache: true
        }).success(function (venues) {
            delay.resolve(venues);
        });

        return delay.promise;
    }

    return {
        getVenues: getVenues
    }
});

controllers.controller('AppCtrl', function (venues, $scope) {
    $scope.venuesPerPage = 3;

    venues.getVenues().then(function (venues) {
        $scope.venues = venues;
        $scope.numVenues = $scope.venues.length;
        $scope.currentPage = 0;
        $scope.currentVenue = 0;
        $scope.numPages = Math.ceil($scope.numVenues / $scope.venuesPerPage) - 1;
    }
});

很抱歉长篇大论,不知道如何准确指定。提前谢谢。

2 个答案:

答案 0 :(得分:3)

策略是利用对象引用。如果将共享数据移动到对象,然后将该对象设置为$scope,则$ scope的任何更改都会直接更改服务对象,因为它们是相同的($scope引用该服务)。

Here's a live sample demonstrating this technique (click).

  <div ng-controller="controller-one">
    <h3>Controller One</h3>
    <input type="text" ng-model="serv.foo">
    <input type="text" ng-model="serv.bar">
  </div>
    <div ng-controller="controller-two">
    <h3>Controller Two</h3>
    <input type="text" ng-model="serv.foo">
    <input type="text" ng-model="serv.bar">
  </div>

JS:

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

app.factory('myService', function() {
  var myService = {
    foo: 'abc',
    bar: '123'
  };
  return myService;
});

app.controller('controller-one', function($scope, myService) {
  $scope.serv = myService;
});

app.controller('controller-two', function($scope, myService) {
  $scope.serv = myService;
});

答案 1 :(得分:2)

我把这个快速地放在一起作为起点。您可以以任何方式重组工厂。一般的想法是,范围内的所有数据现在都已移至工厂服务中的对象。

不是仅使用响应数组解析$http,而是使用包含服务器阵列的更大对象来解析它。由于所有数据现在都在一个对象中,因此可以从任何控制器更新

services.factory('venues', function ($http, $q) {
    var getVenues = function(callback) {
        var delay = $q.defer();

        $http.get('/api/venues', {
            cache: true
        }).then(function (response) {
                /* update data object*/
                venueData.venues=response.data;
                venueData.processVenueData();
                /* resolve with data object*/
                delay.resolve(venueData);
         }).then(callback);

        return delay.promise;
    }

    var processVenueData=function(){
        /* do some data manipulation here*/
        venueData.updateNumPages();
    }


    var venueData={
        venuesPerPage : 3,
        numVenues:null,
        currentVenue:0,
        numPages:null,
        venues:[],
        updateNumPages:function(){
            venueData.numPages = Math.ceil(venueData.numVenues / venueData.venuesPerPage) - 1;
        },
         /* create some common methods used by all controllers*/
        addVenue: function( newVenue){
             venueData.venues.push( newVenue)
        }
    }

    return {
        getVenues: getVenues
    }
});

controllers.controller('AppCtrl', function (venues, $scope) {  

    venues.getVenues(function (venueData) {
      /* now have much bigger object instead of multiple variables in each controller*/
       $scope.venueData=venueData;
    })
});

现在标记参考venueData.venuesvenueData.numPages

通过跨控制器共享方法,您现在只需将带有ng-model的表单对象绑定到具有ng-click="venueData.addVenue( formModel)"(或使用ng-submit)的按钮,您就可以添加新的地点来自任何控制器/指令而无需向控制器添加一些代码