AngularJS Scope在异步调用后不在视图中更新

pet*_*pod 14 scope asynchronous angularjs

在向API发出请求时,我无法在前端更新我的示波器.在后端我可以看到我的$ scope变量的值正在改变,但这并没有在视图中反映出来.

这是我的控制器.

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);
      });
    });  
 }
});
Run Code Online (Sandbox Code Playgroud)

这是我的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>
Run Code Online (Sandbox Code Playgroud)

我尝试了几种解决方案,包括使用$ scope.$ apply(); 但这只会产生常见错误

错误:$ digest已在进行中

以下帖子建议使用$ timeout或$ asyncDefault AngularJS:在调用$ scope时防止错误$ digest正在进行中.$ apply()

我上面的代码使用$ timeout,我没有错误,但视图仍未更新.

帮助赞赏

Vla*_*nek 12

我使用的是AngularJS 1.3+,您可以$scope.$applyAsync()$scope.beers = response.data;声明后立即尝试.

这是Angular文档所说的内容 $applyAsync()

安排$ apply的调用在以后发生.实际时间差异因浏览器而异,但通常约为10毫秒.资源

更新

正如其他人所指出的,你不应该(通常)需要手动触发摘要周期.大多数时候,它只是指向您的应用程序的糟糕设计(或至少不是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()">
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)


jus*_*opi 0

正如评论所建议的,您不需要使用$timeout来触发摘要周期。只要引起变化的用户体验在角度构造的范围内(例如控制器功能、服务等),那么它就应该在摘要周期内体现出来。

根据我从您的帖子中推断出的信息,您可能正在使用搜索输入来访问 API 并获取结果。我建议更改逻辑,以便您在显式事件而不是$watch呃事件上触发搜索。

<input ng-model="search" ng-change="fetch()">
Run Code Online (Sandbox Code Playgroud)

删除$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;  
});
}
Run Code Online (Sandbox Code Playgroud)

我提出这个建议的原因是:

  • 您可以使用 更好地控制ng-change回调的触发方式ng-model-options。这意味着您可以延迟它,可以触发各种 UX 事件等。
  • 您已经保持了更清晰的调用顺序fetch
  • 您可能已经避免了性能和 $digest 问题。