Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
939 views
in Technique[技术] by (71.8m points)

asynchronous - AngularJS Scope not updating in view after async call

I am having trouble updating my scope on the front-end while making a request to an API. On the backend I can see that the value of my $scope variable is changing but this is not being reflected in the views.

Here is my controller.

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

Here is a snippet of my 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>

I've tried several solutions including using $scope.$apply(); but this just creates the common error

Error: $digest already in progress

The following post suggested to use $timeout or $asyncDefault AngularJS : Prevent error $digest already in progress when calling $scope.$apply()

The code I have above uses $timeout and I have no errors but still the view is not updating.

Help appreciated

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I you are using AngularJS 1.3+, you can try $scope.$applyAsync() right after $scope.beers = response.data; statement.

This is what Angular documentation says about $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

Update

As others have pointed out, you should not (usually) need to trigger the digest cycle manually. Most of the times it just points to a bad design (or at least not an AngularJS-friendly design) of your application.

Currently in the OP the fetch method is triggered on $watch. If instead that method was to be triggered by ngChange, the digest cycle should be triggered automatically.

Here is an example what such a code might look like:

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

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...