2013-11-09 22 views
1

我想從服務器中使用Angular應用程序的主控制器中的$資源加載JSON對象。有一些路徑加載部分到ng-view中顯示數據,分頁等。瞭解使用AngularJS承諾,他們將如何幫助解決此問題

這一切工作正常,但我的下一個目標是過濾基於單擊鏈接的數據,並更新URL,以便用戶可以鏈接到過濾的數據(domain.dev/products/brandname)。

只要站點從根URL或其他任何不會將路由調用到產品的URL加載,一切都很好,但只要我試圖從/ products中加載站點,它就會中斷,因爲在路由將部分加載到視圖之前,數據不可用。

我想了解一個承諾是否有助於解決這個問題,如果有的話,從哪裏開始。我一直在做一些關於承諾的閱讀,我相當肯定這是答案,但我無法使它與現有代碼一起工作。

我使用$資源,因爲它看起來很乾淨,但也許$ http會在這裏做得更好,因爲它有更多選項。

簡單地說,當網站從/加載時,一切都很好,因爲使用JSON的部分還沒有,當它們加載時,數據已準備就緒。但是,當加載部分的控制器在網站加載時被調用時,數據不存在,並且當我嘗試設置一些增值時,ProductController會引發錯誤。由於$ scope.products不存在,它沒有長度的方法。我把整個代碼部分包裝在一個帶有ng-show =「products」的div中,但是由於錯誤似乎是在控制器中拋出,所以在這種情況下我不能正常工作。部分仍會加載,但{{vars}}可見。

任何指導,將不勝感激。

編輯:我不是試圖將URL參數發送到端點,我實際上想要所有的數據,然後篩選與Angular。基本上,我希望主應用程序下載所有的數據(並不多),並準備就緒,無論/ products/string是否爲路徑。我的目標是避免爲每個過濾器進行HTTP調用。我有這樣的工作,但只有幾個項目等待HTTP結果的時間太長。我的主要問題是我可以獲取數據,但是當數據從服務器返回時,ProductController已經運行並引發錯誤。基本上,我希望控制器在嘗試運行之前等待數據。

編輯2:我想出了問題,這更多的是我試圖構建我的應用程序的方式。我認爲分離代碼的最好方法是將產品放在自己的控制器中,但也想通過預先加載數據,我需要在主appController中調用服務。那是我的錯誤。一旦我將所有代碼移入appController 並更改了產品路由 中的控制器,它就會按需要工作。我被提示更多地瞭解承諾,這很好,我能夠使用我學到的東西。仍然存在過濾問題,但是這解決了這個問題。

我得到了這個職位的一些幫助:AngularJS: Waiting for an asynchronous call

這裏是工作代碼:

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> 

回答

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

我們得到承諾的迴應:

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

參考

允諾表示未來值,通常是一個異步操作的未來結果,並允許我們定義一次該值變爲可用,或發生 錯誤會發生什麼。

我建議你讀這個好presentation熱諾言工作

+0

謝謝您的回答。我試過你的解決方案,但仍然有問題。似乎沒有返回數據。另外,$資源需要注入到服務中。實際上我並不想將參數傳遞給端點,我想先獲得完整的負載(這不是很多項目),然後使用Angular在數據加載後對其進行過濾。也許我並不清楚這一點。我正在閱讀你所建議的PDF,也許我可以在那裏選擇一些能夠幫助我理解它如何工作的東西。 – Jazzy

+0

雖然這不是確切的正確答案,但它爲我提供了去正確的地方的知識。我會考慮這個答案。 – Jazzy

1

您可以使用resolve$routeProvider來解決這個問題。像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 
}