1

Angular アプリのメイン コントローラーで $resource を使用して、サーバーから JSON オブジェクトを読み込もうとしています。データが表示されたり、ページ分割されたりする ng-view にパーシャルをロードするいくつかのルートがあります。

これで問題なく動作しますが、次の目標は、クリックされたリンクに基づいてデータをフィルタリングし、URL を更新して、ユーザーがそのフィルタリングされたデータ (domain.dev/products/brandname) にリンクできるようにすることです。

サイトがルート URL または製品へのルートを呼び出さないその他の URL から読み込まれる限り、すべて問題ありませんが、/products からサイトを読み込もうとするとすぐにデータが読み込まれないため、サイトが壊れます。ルートがパーシャルをビューにロードする前に使用できます。

約束がこの問題に役立つかどうか、もしそうなら、どこから始めればよいかを理解しようとしています。私は約束についていくつか読んでおり、それが答えだと確信していますが、既存のコードで動作させることができません。

$resource は見栄えが良いので使用していますが、オプションが多いため、ここではおそらく $http の方が適しているでしょう。

簡単に言えば、サイトが / から読み込まれるときは、JSON を使用するパーシャルがまだそこになく、それらが読み込まれるとデータの準備が整っているため、すべて問題ありません。しかし、パーシャルをロードするコントローラーがサイトのロード時に呼び出されると、データが存在せず、変数を設定しようとすると ProductController がエラーをスローします。$scope.products は存在しないため、長さの方法はありません。ng-show="products" を使用して div でラップされたパーシャルのコード全体がありますが、コントローラーでエラーがスローされているように見えるため、この場合は期待どおりに機能しません。パーシャルは引き続き読み込まれますが、{{ vars }} が表示されます。

これに関するガイダンスをいただければ幸いです。

編集: URL パラメーターをエンドポイントに送信しようとしているわけではありません。実際にはすべてのデータを前もって取得したいので、フィルターは Angular で行います。基本的には、/products/string がパスであるかどうかに関係なく、メイン アプリですべてのデータをダウンロードして (それほど多くはありません)、準備を整えておきたいと考えています。私の目標は、フィルターごとに HTTP 呼び出しを行わないようにすることです。私はそれを機能させましたが、HTTP結果を待っているいくつかのアイテムだけでは遅すぎました. 私の主な問題は、データを取得できることですが、サーバーからデータが返されるまでに、ProductController が実行され、エラーがスローされます。基本的に、実行しようとする前にコントローラーがデータを待機するようにします。

編集2:私は問題を理解しました.それは私が自分のアプリを構築しようとしていた方法です. コードを分離する最善の方法は、製品を独自のコントローラーに入れることだと思いましたが、事前にデータをロードしたいので、メインの appController でサービスを呼び出す必要があります。それは私の間違いでした。すべてのコードを appController に移動し、製品ルートのコントローラーを変更すると、期待どおりに機能しました。promise についてもっと学ぶように促されました。これは良いことであり、学んだことを利用することができました。フィルタリングの問題はまだありますが、これで問題は解決します。

この投稿から助けを得ました: 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>
4

2 に答える 2

3

私はあなたの例を少し変更します:

その代わり:

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;
    }); 

promise の応答を取得します。

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

参照

promise は将来の値 (通常は非同期操作の将来の結果) を表し、この値が利用可能になったとき、またはエラーが発生したときに何が起こるかを定義できます。

この良いpresentation熱い約束の作品を読むことをお勧めします

于 2013-11-09T17:08:08.767 に答える
1

resolveonを使用し$routeProviderて、この問題を修正できます。プロパティのように、利用可能なプロパティcontrollerresolveあります。ドキュメントが言及しているように

コントローラーに注入する必要がある依存関係のオプションのマップ。これらの依存関係のいずれかが promise である場合、ルーターは、コントローラーがインスタンス化される前に、それらがすべて解決されるか、1 つが拒否されるのを待ちます。すべてのプロミスが正常に解決された場合、解決されたプロミスの値が注入され、$routeChangeSuccess イベントが発生します。promise のいずれかが拒否された場合、$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
}
于 2013-11-09T17:12:25.303 に答える