【问题标题】:Angular : Pass JSON $http promise to factoryAngular:将 JSON $http 承诺传递给工厂
【发布时间】:2013-07-10 15:49:37
【问题描述】:

目前,我的 Angular 应用如下所示:

工厂在app.js

StoreApp.factory("DataService", function () {

    // create store
    var myStore = new store();

    // create shopping cart
    var myCart = new shoppingCart("Store");

   // return data object with store and cart
   return {
       store: myStore,
       cart: myCart
   };
});

controller.js

    function storeController($scope, $http, $routeParams, $location, DataService) {

            $scope.store = DataService.store;
            $scope.cart = DataService.cart;

            // use routing to pick the selected product
            if ($routeParams.productUrlTitle != null) {
                $scope.product = $scope.store.getProduct($routeParams.productUrlTitle) || $scope.store.getHero($routeParams.productUrlTitle);
            }

            $scope.predicate = '-price';
            $scope.store.isCart = $location.path() == "/cart";
}

store.js(下)是我的问题所在 - 目前this.products[] 接受内联分配。我需要这个来加载一个外部 JSON 文件(也在下面)。我已经尝试了几件事,从包含/传递promisevar myStore = new store();,到实际包含$http.get().then() 配对在store.js 内部——但无济于事。

store.js

function store() {
   this.products = [
       new product("USD", 20, "https://foo.jpg", "Name", "Description"),
   new product("USD", 20, "https://bar.jpg", "Name", "Description"),
];

}
store.prototype.getProduct = function (urlTitle) {
    for (var i = 0; i < this.products.length; i++) {
    if (this.products[i].urlTitle == urlTitle)
        return this.products[i];
    }
    return null;
}

payload.json

[
    {
    "currency": "usd",
    "cost": 1000,
    "image_url": "https://whatever.domain/someimage.jpg",
    "id": "xyz",
    "name": "A title",
    "description": "Some details"
   },
   ...
]

对于那些感兴趣的人,我的项目基于此:A Shopping Cart Application Built with AngularJS

提前非常感谢。


更新

我能够完成我想要的,但我不确定这是最好的(阅读:正确)方法。简而言之,我添加了一个名为“InventoryService”的新工厂,并将其传递给我的控制器。

app.js

// New Factory Added

StoreApp.factory('InventoryService', ['$http', '$rootScope',
    function ($http, $rootScope) {
        var inventory = [];

        return {
            getInventory: function () {
                return $http.get('http://localhost/ShoppingCart/payload.json').then(function (response) {
                    inventory = response;
                    $rootScope.$broadcast('handleInventoryService', inventory);
                    return inventory;
                })
            }
        };
    }
]);

controller.js

function storeController($scope, $http, $routeParams, $location, InventoryService, DataService) {

    $scope.name = 'inventory';
    (function () {
        InventoryService.getInventory().then(function (inventory) {
            $scope.inventory = inventory;

            for (var i = 0; i < $scope.inventory.data.length; i++) {
                if ($scope.inventory.data[i].id == '11ca3ea26f0e431eb996a401f292581f2') {
                    DataService.store.hero.push(
                        new product(
                            $scope.inventory.data[i].id,
                            $scope.inventory.data[i].image_url,
                            $scope.inventory.data[i].name,
                            $scope.inventory.data[i].description,
                            $scope.inventory.data[i].cost
                        )
                    );
                } else {
                    DataService.store.products.push(
                        new product(
                            $scope.inventory.data[i].id,
                            $scope.inventory.data[i].image_url,
                            $scope.inventory.data[i].name,
                            $scope.inventory.data[i].description,
                            $scope.inventory.data[i].cost
                        )
                    );
                }
            }

            // get store and cart from service
            $scope.store = DataService.store;
            $scope.cart = DataService.cart;
 ...

store.html部分

<div ng-include src="'partials/header.html'"></div>

<div ng-repeat="product in store.hero" class="row-fluid">
    <div class="span12">
        <div class="span4">
            <a href="#/products/{{product.urlTitle}}">
                <img class="img-polaroid" ng-src="{{product.image_url}}" title="{{product.name}}" />
            </a>
        </div>
        <div class="span8">
            <h1 class="tango-tang weight-100">
                {{product.name}}
            </h1>
            <hr />
            <div class="row-fluid">
                <div class="span7">
                    <p>
                        {{product.description}} 
                    </p>
                </div>
                <div class="span5">
                    <div class="well">
                        <h1 class="weight-300 text-center">
                            {{product.price | currency}}
                        </h1>
                    </div>
                    <button class="btn btn-success btn-medium btn-block" ng-click="cart.addItem(product.sku, product.image_url, product.name, product.price, 1)">
                            <i class="icon-plus"></i> Add to Cart 
                    </button> 
                    <a href="#/products/{{product.urlTitle}}" class="btn btn-block">
                        <i class="icon-list"></i> Details
                    </a> 
                </div>
            </div>
        </div>
    </div>
</div>

【问题讨论】:

  • $http 和 $q 应该做你想做的事,你说你试过承诺,你能包括那段代码吗?
  • @jaux - 查看我的更新。有更好的方法吗?
  • 如果InventoryService的目的只是用初始数据填充两个数组,我认为没有必要。你可以尝试让productshero 两个promise,稍后当HTTP 响应时,一次解决两个延迟对象。将您的 HTML 发布在您实际使用 productshero 的位置,以便我们更好地了解您的使用情况。
  • @jaux - 添加了hero 的标记,它[几乎] 与products 相同。

标签: javascript json angularjs promise


【解决方案1】:

正如我在评论中概述的那样,在您的情况下,InventoryService 不是必需的, $q 和 $http.get 就足够了。

引自cmets:

您可以尝试让 products 和 hero 都承诺,稍后当 HTTP 响应时,一次解决两个延迟对象。

代码:

App.factory('DataService', function($http, $q) {
    function Store() {
        var heroDeferred = $q.defer();
        var productsDeferred = $q.defer();

        this.hero = heroDeferred.promise;
        this.products = productsDeferred.promise;

        $http.get('/path/to/payload.json').success(function(data) {
            var hero = [];
            var products = [];

            for (var i = 0, len = data.length; i < len; i++) {
                var prod = data[i];
                if (prod.id === 'xyz') {
                    hero.push(prod);
                } else {
                    products.push(prod);
                }
            }

            heroDeferred.resolve(hero);
            productsDeferred.resolve(products);
        });
    }

    Store.prototype.getProduct = function(urlTitle) {
        return this.products.then(function(products) {
            for (var i = 0; i < products.length; i++) { // MUST use products, it's the real value; this.products is a promise
                if (products[i].urlTitle == urlTitle)
                    return products[i];
            }
            return null;
        });
    };

    ...
    return {
        store: new Store()
        ...
    };
});

http://plnkr.co/edit/qff7HYyJnSdEUngeOWVb

【讨论】:

  • 这很好用。它创建的唯一问题是$scope.store 不再有权访问store.prototype.getProductstore.prototype.getHero,这破坏了允许您深入了解每个产品的详细信息的路线。见// use routing to pick the selected productcontroller.js
  • @couzzi this.products 现在是一个承诺,所以store.getProduct 也应该返回一个承诺。看看文档中的“Chaining promises”,如果你仍然无法弄清楚,请告诉我。
  • 我尽了最大努力,这是我所得到的:$scope.product = $scope.store.hero.then(function(result) { return $scope.store.getHero(result[0].urlTitle); }); 没有骰子。
  • 谢谢!这是完美的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
  • 2014-09-27
  • 1970-01-01
  • 2013-08-09
  • 1970-01-01
相关资源
最近更新 更多