2016-01-20 76 views
13

我在向API發出請求時更新前端範圍時遇到問題。在後端,我可以看到我的$ scope變量的值正在改變,但這並未反映在視圖中。AngularJS範圍在異步調用後未在視圖中更新

這是我的控制器。

Controllers.controller('searchCtrl', 
function($scope, $http, $timeout) { 
    $scope.$watch('search', function() { 
     fetch(); 
    }); 

$scope.search = "Sherlock Holmes"; 

function fetch(){ 
    var query = "http://api.com/v2/search?q=" + $scope.search + "&key=[API KEY]&format=json"; 
    $timeout(function(){ 
     $http.get(query) 
     .then(function(response){ 
     $scope.beers = response.data; 
     console.log($scope.beers); 
     }); 
    }); 
} 
}); 

這裏是我的HTML片段

<div ng-if="!beers"> 
    Loading results... 
</div> 
<p>Beers: {{beers}}</p> 
<div ng-if="beers.status==='success'"> 

    <div class='row'> 
    <div class='col-xs-8 .col-lg-8' ng-repeat="beer in beers.data track by $index" ng-if="beer.style"> 
    <h2>{{beer.name}}</h2>   
    <p>{{beer.style.description}}</p> 
    <hr> 
    </div> 
    </div> 
</div> 

<div ng-if="beers.status==='failure'"> 
    <p>No results found.</p> 
</div> 

我已經嘗試了幾種解決方案,包括使用$範圍$適用()。但這只是創建了常見的錯誤

Error: $digest already in progress

以下後建議使用$超時或$ asyncDefault AngularJS : Prevent error $digest already in progress when calling $scope.$apply()

我上面的代碼使用$超時,我沒有錯誤,但仍然是視圖不更新。

幫助表示讚賞

+2

你不應該需要'timeout' - '$ http'會觸發'$ digest'循環 - 你確定數據會回來嗎? – tymeJV

+0

向請求添加錯誤處理程序。還要檢查開發工具網絡以確保請求成功並返回預期的結果。聽起來像ajax問題 – charlietfl

+0

同意這個代碼不需要超時,並且$ http應該觸發一個摘要循環。 $ http response中的console.log是否顯示$ scope.beers更新? –

回答

0

作爲意見建議,你不應該需要使用$timeout觸發消化週期。只要引發改變的UX在角結構(例如,控制器功能,服務等)的範圍內,則它應該在摘要週期內出現。

基於我可以從您的文章中推斷出的內容,您可能正在使用搜索輸入來打擊帶結果的API。我建議改變邏輯,讓你在明確的事件上觸發你的搜索,而不是在$watch呃。

<input ng-model="search" ng-change="fetch()"> 

卸下$watch邏輯和$timeout包裝。

function fetch(){ 
    var query = "http://api.com/v2/search?q=" + $scope.search + "&key=[API KEY]&format=json"; 
$http.get(query) 
.then(function(response){ 
    $scope.beers = response.data; 
    console.log($scope.beers); 

    //it's a good habit to return your data in the promise APIs 
    return $scope.beers; 
}); 
} 

的原因,我做這個建議是:

  • 你的ng-change回調如何使用ng-model-options引發更精細的控制。這意味着你可以延遲它,你可以觸發各種UX事件等。
  • 你已經保持了一個更清晰的如何調用fetch的順序。
  • 您可能已經避免了性能和$摘要問題。
+0

嘿。讓我試試看!也許我對觀察者太喜歡了 – peterpod

+0

我希望它能解決問題。通常,我使用'watch'來表示某些用戶體驗不直接觸發的事物(換言之,並非由現有的指令或其他ng結構),以及在需要挖掘DOM事件的指令中,我不想連接隔離範圍等。 – jusopi

+0

我嘗試了ng-change的建議,但是我決定在這裏簡單地做ng-submit。即使採用這種方法,視圖也不會更新。我的consolelog會在每個表單提交中打印出新的json響應,但範圍變量不會更新。我更新了我的帖子,上面顯示我的html – peterpod

11

我你使用的是AngularJS 1.3+,你可以試試$scope.$applyAsync()之後$scope.beers = response.data;聲明。

這就是角文件說,大約$applyAsync()

Schedule the invocation of $apply to occur at a later time. The actual time difference varies across browsers, but is typically around ~10 milliseconds. Source

更新

正如其他人所指出的那樣,你不應該(通常)需要手動觸發消化週期。大多數情況下,它只是指向應用程序的糟糕設計(或者至少不是AngularJS友好的設計)。

目前在OP中fetch方法在$ watch上觸發。如果該方法是由ngChange觸發的,那麼應該自動觸發摘要循環。

下面是一個例子這樣的代碼可能是什麼樣子:

HTML

// please note the "controller as" syntax would be preferred, but that is out of the scope of this question/answer 
<input ng-model="search" ng-change="fetchBeers()"> 

的JavaScript

function SearchController($scope, $http) { 

    $scope.search = "Sherlock Holmes"; 

    $scope.fetchBeers = function() { 
     const query = `http://api.com/v2/search?q=${$scope.search}&key=[API KEY]&format=json`; 
     $http.get(query).then(response => $scope.beers = response.data); 
    }; 

} 
0

嗨我解決了這個問題,但我不確定爲什麼這改變了任何東西。在JS Fiddle上重新排列我的代碼我只是把所有的部分放入index.html文件中,並且請求和範圍變量順利更新。是否有可能與我的HTML上面的控制器衝突?

<body ng-app="beerify" ng-controller='searchCtrl'> 

<nav class="navbar navbar-inverse navbar-fixed-top"> 
    <div class="container"><!-- nav bar code --> 
    </div> 
</nav> 

<!-- Main jumbotron for a primary marketing message or call to action --> 
<div class="jumbotron"> 
    <div class="container"> 
    <h1>Title</h1> 

    <form ng-submit="fetch()"> 
     <div class="input-group"> 
      <input type="text" ng-model="search" 
       class="form-control" placeholder="Search the name of a beer" name="srch-term" id="srch-term"> 
      <div class="input-group-btn"> 
       <button class="btn btn-default" type="submit"><i class="glyphicon glyphicon-search"></i></button> 
      </div> 
     </div> 
    </form> 

    </div> 
</div> 

<div class="container"> 

    <div ng-if="!beers"> 
    Loading results... 
    </div> 
    <div ng-if="beers.status==='success'"> 
    <div class='row'> 
     <div class='col-xs-8 .col-lg-8' ng-repeat="beer in beers.data track by $index" ng-if="beer.style"> 
     <!-- ng-if will make sure there is some information being displayed 
      for each beer --> 
     <h2>{{beer.name}}</h2> 
     <h3>{{beer.style.name}}</h3> 
     <p>AbvMin: {{beer.abv}}</p> 
     <p>AbvMax: {{beer.ibu}}</p>  
     <p>{{beer.style.description}}</p> 
     <hr> 
     </div> 
    </div> 
    </div> 

    <div ng-if="beers.status==='failure'"> 
    <p>No results found.</p> 
    </div> 
</body>