Je ne parviens pas à mettre à jour mon étendue sur l'interface frontale lors d'une requête auprès d'une API. Sur le backend, je peux voir que la valeur de ma variable $ scope est en train de changer, mais cela ne se reflète pas dans les vues.
Voici mon contrôleur.
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);
});
});
}
});
Voici un extrait de mon code 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>
J'ai essayé plusieurs solutions, notamment en utilisant $ scope. $ Apply (); mais cela ne fait que créer l'erreur commune
Erreur: $ digest déjà en cours
Le message suivant suggérait d'utiliser $ timeout ou $ asyncDefault AngularJS: Empêcher l'erreur $ digest déjà en cours lors de l'appel de $ scope. $ Apply ()
Le code que j'ai ci-dessus utilise $ timeout et je n'ai aucune erreur mais la vue n'est toujours pas mise à jour.
Aide appréciée
Si vous utilisez AngularJS 1.3+, vous pouvez essayer $scope.$applyAsync()
juste après l’instruction $scope.beers = response.data;
.
C’est ce que dit la documentation de Angular à propos de $applyAsync()
Planifiez l'invocation de $ apply pour qu'elle se produise ultérieurement. La différence de temps réelle varie d’un navigateur à l’autre, mais elle est généralement d’environ 10 millisecondes. La source
Mettre à jour
Comme d'autres l'ont souligné, vous ne devriez pas (généralement) avoir besoin de déclencher le cycle de digestion manuellement. La plupart du temps, cela ne fait que signaler une mauvaise conception (ou du moins pas une conception conviviale pour AngularJS) de votre application.
Actuellement dans l'OP, la méthode fetch
est déclenchée sur $ watch. Si au lieu de cela, cette méthode devait être déclenchée par ngChange
, le cycle de résumé devrait être déclenché automatiquement.
Voici un exemple à quoi un tel code pourrait ressembler:
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);
};
}
Hé les gars, j'ai résolu le problème mais je ne sais pas exactement pourquoi cela a changé quoi que ce soit. Réorganisation de mon code sur JS Fiddle Je viens de placer tous mes partiels dans le fichier index.html, comme ceci, et les requêtes et les variables de portée ont été mises à jour en douceur. Y at-il peut-être un conflit de contrôleur avec mon HTML ci-dessus?
<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>
Comme le suggèrent les commentaires, vous ne devriez pas avoir besoin d'utiliser $timeout
pour déclencher un cycle de résumé. Tant que l'UX qui provoque le changement se trouve dans limite d'une construction angulaire (par exemple, fonction du contrôleur, service, etc.), elle doit se manifester dans le cycle de résumé.
D'après ce que je peux déduire de votre message, vous utilisez probablement une entrée de recherche pour atteindre une API avec des résultats. Je vous conseillerais de modifier la logique de manière à déclencher votre recherche sur un événement explicite plutôt que sur le $watch
er.
<input ng-model="search" ng-change="fetch()">
Supprimez la logique $watch
et le wrapper $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;
});
}
Les raisons pour lesquelles je fais cette recommandation sont:
ng-change
est déclenché à l'aide de ng-model-options
. Cela signifie que vous pouvez y mettre un délai, vous pouvez déclencher différents événements UX, etc.fetch
est appelé.