2013-02-18 46 views
6

最初在我的應用程序中,我創建了具有非常基本的$ http調用的控制器,通過從url($ routeParams)獲取對象的ID來獲取資源。 Ng-repeat正確顯示結果。AngularJS ng-repeat與服務中的數據

但是,我注意到在後來的視圖(不同的控制器)刷新刷新數據並打破了頁面。因此,我在多個控制器上創建了一項服務功能,以檢查數據是否可用,並如下作出反應:

1)如果資源已定義,則返回它(無API調用) 2)如果資源沒有定義,從url獲取id並從API獲取。3)如果資源未定義&你不能得到ID,只返回false。

但是,這打破了代碼:服務返回數據之前呈現的模板,並且ng-repeat沒有更新。代碼如下所示:

angular.module('myApp', ['ngCookies']) 
    .config(...) 
    .service('myService', ['$cookies', '$http', function($cookies, $http) { 
     myData = {}; 

     return { 
      getData:function(dataID) { 
       if(myData.name) {return myData); 
       else if (dataID && dataID !== '') { 
        $http.get('/api/data/' + dataID) 
         .success(function(data) { 
          myData = data.object; 
          $cookies.dataID = data.object.id; 
          return myData; 
         } 
       } 
       else { return false; } 
      } 
     } 
    }]); 

function myCtrl($scope, $http, $routeParams, myService) { 
    $scope.data = myService.getData($routeParams.dataID); 

    ... 
} 

這裏是模板。它是用jade表示的,而不是尖括號,你只需在括號後面加括號,括號後加內容即可。

h2 My heading 
ul 
    li(ng-repeat='option in data') 
     a(href="#", ng-click='someFuncInCtrl(option.name)') {{ option.name }} 

當控制器做了$ http.get本身,NG-重複工作得很好,因爲$範圍是在「.success」回調更新。現在有一個服務在稍微延遲後返回數據,「$ scope.data」只是未定義的,ng-repeat列表是空的。

在返回「return myData」之前,我使用了console.log來檢查myData,並且myData正在工作,只是沒有及時返回,並且無論何時出現任何原因,只要$ scope得到的列表都不會更新數據。

我看着一個使用$ routeProvider的解決方案...但是這使得從URL中獲取ID具有挑戰性,因爲解析對象似乎無法訪問$ routeParams。我知道$ scope。$ apply應該可以幫助更新範圍,當它被外部函數改變時......但我不知道該把它放在哪裏。 SO上的most similar problem沒有使用服務。

我想:

$scope.$apply($scope.data = myService.getData($routeParams.dataID)); 

而且

$scope.$apply(function() { 
    $scope.data = myService($routeParams.dataID); 
}); 

這兩次我只得到了錯誤:$已經在進行中消化。

+0

可能想嘗試在教程角文檔站點的'寧靜service'方法。返回一個承諾。 http://docs.angularjs.org/tutorial/step_11 – charlietfl 2013-02-19 00:01:10

回答

11

問題在於您與服務交互的方式。由於您的getData函數可以同時返回同步和/或異步信息,因此不能只使用正常的return(s)。

$http.get('/api/data/' + dataID) 
    .success(function(data) { 
     myData = data.object; 
     $cookies.dataID = data.object.id; 
     return myData; 
    }); 

在上面的代碼,因爲它會在$http.get成功回調的上下文中執行(不是getData調用堆棧上)將不會從getData返回任何的return

處理同步和異步服務請求的最佳方法是使用promises

getData功能應該是這個樣子:

getData:function(dataID) { 
    var deferred = $q.defer(); 
    if(myData.name) { 
     deferred.resolve(myData); 
    } else if (dataID && dataID !== '') { 
     $http.get('/api/data/' + dataID) 
      .success(function(data) { 
       myData = data.object; 
       $cookies.dataID = data.object.id; 
       deferred.resolve(myData); 
       // update angular's scopes 
       $rootScope.$$phase || $rootScope.$apply(); 
      }); 
    } else { 
     deferred.reject(); 
    } 

    return deferred.promise; 
} 

注意:您需要在您的服務注入$rootScope

而且您的控制器上:

function myCtrl($scope, $http, $routeParams, myService) { 
    myService.getData($routeParams.dataID).then(function(data) { 
     // request was successful 
     $scope.data = data;   
    }, function() { 
     // request failed (same as your 'return false') 
     $scope.data = undefined; 
    }); 
} 
+0

非常感謝。還將$ q注入服務。像魅力一樣工作。 – ansorensen 2013-02-19 06:15:26

+0

謝謝,謝謝!我需要注入$ rootScope到我的服務來更新角度的範圍後解決我的延期(通過$ rootScope。$$階段|| $ rootScope。$ apply()) – remi 2013-07-31 05:29:12