AngularJS 1.2在服务中存储数据数组

时间:2014-02-12 18:27:46

标签: angularjs angularjs-service

我有一个问题,寻求建议,关于如何将存储在服务数组中的数据提供给控制器,因为在1.2中删除了解包承诺。

示例:

  1. 路线1包含物品清单
  2. 路线二包含用于添加新项目的表单
  3. 一旦项目从路线牵引中保存,用户将被重定向回路线一。
  4. 当路由一个最初加载时,服务将向服务器请求项目,将项目存储在服务中的数组中,因此每次请求路由一后只返回一个数组。保存项目时,该项目已被推送到服务中的数组。

    如果我在初始加载时等待路由器1的控制器中的承诺,没有问题,因为响应被发回,但是在此之后路由一个的每个请求都会返回错误,因为我返回了一个数组。

    关于如何在1.2中完成这样的事情的任何想法?

    app.factory('Items',function($http) {
        var items = [];
        return {
            list: function() {
                if (items.length == 0) {    // items array is empty so populate it and return list from server to controller
                    return $http.get('/?items').then(function(response) {
                        items = response.data.items;
                        return response.data.items;
                    });
                }
                return items;   // items exist already so just return the array
            },
            save: function(item) {
                return $http.post('/',{item:item}).then(function(response) {
                    items.push(item);
                    return response;
                });
            }
        }
    });
    
    app.controller('RouteOne',function($scope,Items) {
        Items.list().then(function(response) {
            $scope.items = response;
        });
    
        /* used to be this before unwrapped promises were removed
        $scope.items = Items.list();
        */
    
    });
    
    app.controller('RouteTwo',function($scope,Items) {
        $scope.new_item = {};
        $scope.addItem = function() {
            Items.save($scope.new_item).then(function(response) {
                $location.path('/');    // back to route one
            });  
        };
    });
    

2 个答案:

答案 0 :(得分:5)

您可以让服务返回自己的承诺,可以使用缓存值或$ http承诺的结果来解析。我没有对此进行过全面测试,但它可能看起来像这样:

app.factory('Items', function($q, $http) {
    var items = [];
    return {
        list: function() {
            var deferred = $q.defer();
            if (items.length == 0) {    // items array is empty so populate it and return list from server to controller
                $http.get('/?items').then(function(response) {
                    items = response.data.items;
                    deferred.resolve(response.data.items);
                });
            } else {
                deferred.resolve(items);   // items exist already so just return the array
            }
            return deferred.promise;
        },
        save: function(item) {
            return $http.post('/',{item:item}).then(function(response) {
                items.push(item);
                return response;
            });
        }
    }
});

app.controller('RouteOne',function($scope,Items) {
    Items.list().then(function(response) {
        $scope.items = response;
    });

});

此外,根据您的特定用例,您可以将延迟移动到服务级别而不是功能级别,因为您只需要调用一次,但是我编写它的方式稍微灵活一点想要清除项目数组。

答案 1 :(得分:2)

由于XHR调用

,必须修改下面给出的解决方案

此示例的主要思想是使用简单的js绑定对模型的引用。

Items.save必须始终返回对其本地范围数组items

的引用

I made you a jsfiddle

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

app.config(function ($stateProvider) {
    $stateProvider
        .state('one', {
            url: '/',
            template: '<ul><li data-ng-repeat="item in items">{{item.value}}</li></ul><a href=#/two>Route two</a>',
            controller: 'RouteOne'
        })
        .state('two', {
            url: '/two',
            template: '<input data-ng-model="new_item.value"></input><button data-ng-click="addItem()">Add item</button>',
            controller: 'RouteTwo'
        });
});

app.run(function ($state) {
    $state.go('one');
});

app.factory('Items',function($http) {
    var items = [];
    return {
        list: function() {
            if (items.length === 0) {    // items array is empty so populate it and return list from server to controller
                // i just modified a little the request for jsfiddle
                $http.get('/echo/jsonp/?items=[{"value": 1},{"value": 2},{"value": 3},{"value": 4},{"value": 5}]').then(function(response) {

                    // you won't need next line  with a real server
                    response.data = JSON.parse(response.data.items);
                    Array.prototype.push.apply(items, response.data);
                });

                // simply always return the reference to items
                // as it will be populated later
                return items;
            }
            return items;   // items exist already so just return the array
        },
        save: function(item) {
            return $http.post('/echo/jsonp/',{item:item}).then(function(response) {
                items.push(item);
                return response;
            });
        }
    }
});

app.controller('RouteOne',function($scope,Items) {
    // don't do anything as you the binding does the work for you
    $scope.items = Items.list();
});

app.controller('RouteTwo',function($scope,Items, $location) {
    $scope.new_item = {};
    $scope.addItem = function() {
        Items.save($scope.new_item).then(function(response) {
            $location.path('/');    // back to route one
        });  
    };
});