AngularJS Scope not updating in view after async call AngularJS Scope not updating in view after async call angularjs angularjs

AngularJS Scope not updating in view after async call


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


As the comments suggest, you shouldn't need to use $timeout to trigger a digest cycle. As long as the UX that elicits the change is within the confines of an angular construct (e.g. controller function, service, etc.) then it should manifest within the digest cycle.

Based on what I can infer from your post, you are probably using a search input to hit an API with results. I'd recommend changing the logic up such that you are triggering your search on an explicit event rather than the $watcher.

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

Remove the $watch logic and the $timeout wrapper.

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

The reasons I make this recommendation is:

  • You have finer control of how the ng-change callback is triggered using ng-model-options. This means you can put a delay on it, you can trigger for various UX events, etc.
  • You've maintained a clearer sequence of how fetch is called.
  • You have possibly avoided performance and $digest issues.


Hey guys I solved the issue but I'm not sure exactly why this changed anything. Rearranging my code on JS Fiddle I just put all my partials into the index.html file like so and the requests and scope variables updated smoothly. Is was there perhaps a controller conflict with my html above?

<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>