了解使用AngularJS承诺,他们将如何帮助解决这个问题

Understanding using AngularJS promises, how would they help solve this issue

本文关键字:帮助 解决 问题 何帮助 AngularJS 承诺 他们将 了解      更新时间:2023-09-26

我正在尝试使用 Angular 应用程序主控制器中的$resource从服务器加载 JSON 对象。有一些路由将部分加载到 ng-view 中,其中显示数据、分页等。

这一切都工作正常,但我的下一个目标是根据单击的链接过滤数据,并更新 URL,以便用户可以链接到过滤后的数据 (domain.dev/products/brandname)。

只要网站从根 URL 或任何其他不调用产品路由的 URL 加载,一切都很好,但是一旦我尝试从/products 加载网站,它就会中断,因为在路由将部分加载到视图中之前数据不可用。

我试图了解承诺是否有助于解决这个问题,如果是,从哪里开始。我一直在阅读一些关于承诺的内容,我相当确定这就是答案,但我无法让它与现有代码一起使用。

我正在使用$resource因为它看起来很干净,但也许$http在这里会做得更好,因为它有更多的选择。

简而言之,当站点从/加载时,一切都很好,因为使用 JSON 的部分尚不存在,加载时,数据已准备就绪。但是,当加载部件的控制器在站点加载时被调用时,数据不存在,并且当我尝试设置一些变量时,产品控制器会引发错误。 由于$scope.products不存在,因此它没有长度方法。我将部分代码中的整个代码包装在带有 ng-show="products" 的div 中,但在这种情况下,这并没有像我预期的那样工作,因为错误似乎在控制器中抛出。部分仍然加载,但 {{ vars }} 可见。

如能就此提供任何指导,将不胜感激。

编辑:我没有尝试将URL参数发送到端点,我实际上想要预先提供所有数据,然后使用Angular进行过滤。基本上,我希望主应用程序下载所有数据(不多)并准备好它,无论/products/string 是否是路径。我的目标是避免为每个过滤器进行 HTTP 调用。我有那个工作,但对于等待HTTP结果的几个项目来说,延迟太长了。我的主要问题是我可以获取数据,但是当数据从服务器返回时,ProductController 已经运行并抛出错误。基本上,我希望控制器在尝试运行之前等待数据。

编辑2:我想出了问题所在,这更多的是我尝试构建应用程序的方式。我认为分离代码的最佳方法是将产品内容放在自己的控制器中,但是由于还想预先加载数据,我需要在主appController中调用服务。那是我的错误。一旦我将所有代码移动到应用程序控制器中并更改产品路由中的控制器,它就会按预期工作。我被提示学习更多关于承诺的知识,这很好,我能够使用我学到的东西。仍然存在过滤问题,但这解决了这个问题。

我从这篇文章中得到了一些帮助:AngularJS:等待异步调用

这是工作代码:

elite.controller('productController', function($scope, $routeParams, $rootScope, $location, Products){
    $scope.brand = $routeParams.brand;
    $rootScope.productPagination = function(){
        $scope.currentPage = 1;
        $scope.numPerPage = 10;
        $scope.maxSize = 6;    
        $scope.totalItems = $rootScope.products.length;
        $scope.numPages =  Math.ceil($scope.totalItems / $scope.numPerPage); 
        $scope.$watch('currentPage + numPerPage', function() {
            var begin = (($scope.currentPage - 1) * $scope.numPerPage)
            , end = begin + $scope.numPerPage;
            $scope.filteredProducts = $rootScope.products.slice(begin, end);
        }); 
    }
    if (!$rootScope.products){
        Products.getProducts().then(function(data){
            $rootScope.products = data.products;
            $rootScope.productPagination();
        });
    }else{
        $rootScope.productPagination();
    }
});

这是到目前为止的应用程序(精简):

var elite = angular.module("elite", ["ngResource", "ngSanitize", "ui.bootstrap"]);
elite.config(['$routeProvider', function($routeProvider){
    $routeProvider.when('/', {
        templateUrl: 'partials/home.html', 
        controller: 'homeController'
    })
    $routeProvider.when('/products', {
        templateUrl:'partials/products.html', 
        controller: 'productController'
    })
    $routeProvider.when('/products/:brand', {
        templateUrl:'partials/products.html', 
        controller: 'productController'
    })
    $routeProvider.otherwise({redirectTo :'/'})
}]);

elite.factory('Products', function($resource){
    return $resource("/products")
});

elite.controller('appController', function($scope, $location, $routeParams, Products){ 
    Products.get({},function (data){
        $scope.products = data.products;
    });  
});
elite.controller('productController', function($scope, $location, $routeParams, $resource){
    $scope.brand = $routeParams.brand;
    $scope.currentPage = 1;
    $scope.numPerPage = 10;
    $scope.maxSize = 6;
    $scope.$watch($scope.products, function(){
        $scope.numPages =  Math.ceil($scope.products.length / $scope.numPerPage); 
        $scope.$watch('currentPage + numPerPage', function() {
            var begin = (($scope.currentPage - 1) * $scope.numPerPage)
            , end = begin + $scope.numPerPage;
            $scope.totalItems = $scope.products.length;
            $scope.filteredProducts = $scope.products.slice(begin, end);
        }); 
    });
});


<div ng-show="products">
    <h2>{{ brand }} products...</h2>
    <h4>{{products.length}} items</h4>
    <pagination ng-show="numPages" total-items="totalItems" page="currentPage" max-size="maxSize" class="pagination-small" boundary-links="true" rotate="false" num-pages="numPages"></pagination>
    <table class="table table-striped">
        <tr ng-repeat="product in filteredProducts">
            <td>{{product.brand}}</td>
            <td>{{product.title}}</td>
            <td ng-bind="product.priceDealer | currency"></td>
            <td>{{product.msrp | currency}}<td>
        </tr>
    </table>
</div>

我会稍微改变一下你的例子:

相反:

elite.factory('Products', function($resource){
    return $resource("/products")
}); 

我们可以写:

elite..factory('Products', function($q){
        var data = $resource('/products', {},
        {
          query: {method:'GET', params:{}}}
        );
       // however I prefer to use `$http.get` instead `$resource`
         var factory = {
            query: function (selectedSubject) {
                var deferred = $q.defer();              
                 deferred.resolve(data);                
                return deferred.promise;
            }
        }
        return factory;        
    });

之后,控制器端:

相反:

Products.get({},function (data){
        $scope.products = data.products;
    }); 

我们得到承诺的回应:

    Products.query()
                    .then(function (result) {
                      $scope.products = data.products;
                    }, function (result) {
                        alert("Error: No data returned");
                    });

参考

承诺表示未来值,通常是异步操作的未来结果,并允许我们定义一旦该值可用或当 发生错误。

我建议你阅读这个好的演示文稿热门承诺工作

您可以使用

$routeProvider上的resolve来解决此问题。像controller酒店一样,有一个resolve物业可用。正如文件所提到的

应注入到 控制器。如果这些依赖项中的任何一个是承诺,路由器将 等待它们全部解决或一个被拒绝,然后再 控制器被实例化。如果所有承诺都已解决 成功,注入已解决的承诺的值,并且 $routeChangeSuccess事件被触发。如果任何承诺是 已拒绝 触发$routeChangeError事件。

您的定义变为

$routeProvider.when('/products/:brand', {
        templateUrl:'partials/products.html', 
        controller: 'productController',
        resolve: {
                    brand:function($resource, $route) {
                       //Get the param values from $route.current.params
                       // implement the method that return a promise which resolves to brand data or product data.
                  }
        },
    })

然后,您可以在控制器中获取此数据

function BrandController($scope,brand) {
   //access brand data here
}