2016-01-20 81 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> 
相关问题