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

时间:2016-01-20 18:38:56

标签: angularjs asynchronous scope

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

这是我的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>

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

  

错误:$ digest已在进行中

以下帖子建议使用 $ timeout 或$ asyncDefault AngularJS : Prevent error $digest already in progress when calling $scope.$apply()

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

帮助表示赞赏

3 个答案:

答案 0 :(得分:12)

我使用的是AngularJS 1.3+,您可以在4语句后立即尝试4

这是Angular文档中关于$scope.$applyAsync()

的内容
  

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

<强>更新

正如其他人所指出的,你不应该(通常)需要手动触发摘要周期。大多数时候它只是指出你的应用程序的糟糕设计(或者至少不是AngularJS友好设计)。

目前在OP中,$ watch会触发$scope.beers = response.data;方法。如果该方法由$applyAsync()触发,则应自动触发摘要周期。

以下是此类代码的示例:

<强> HTML

fetch

<强>的JavaScript

ngChange

答案 1 :(得分:0)

正如评论所示,您不应该使用$timeout来触发摘要周期。只要引起变化的UX在角度构造的 confines 内(例如控制器功能,服务等),它就应该在摘要周期内显现。

根据我在帖子中推断的内容,您可能正在使用搜索输入来搜索带有结果的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
  • 您可能已经避免了性能和$ digest问题。

答案 2 :(得分: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>