AngularJS n'est pas rafraîchissant ngRépétez lors de la mise à jour du tableau

J'ai parfois de sérieux problèmes pour comprendre AngularJS. J'ai donc un tableau de base dans mon contrôleur comme

$scope.items = ["a","b","c"] 

Je ne supporte pas mon modèle sur le tableau des éléments ng-repeat = "item in items". Super straightfoward jusqu'à présent. Après quelques actions UX, je souhaite pousser de nouvelles choses sur mon tableau.

  $scope.items.push("something"); 

Ainsi, 50% du temps, le nouvel élément est ajouté à la vue. Mais l'autre 50%, rien ne se passe. Et c'est comme super frustrant; Bc si j'enveloppe cela dans $ scope. $ Apply (), j'ai eu une erreur "$ digest already in progress". Envelopper cela en $ timeout non pas non plus.

Et lorsque j'observe la portée de mon élément à l'aide de l'extension Chrome; Je peux voir les nouvelles données et la valeur $ scope.items est correcte. Mais la vue est juste de ne pas prendre soin de l'ajouter au DOM.

Merci!

Vous modifiez la portée en dehors du cycle $digest de angular 50% du temps.

S'il y a un rappel qui ne provient pas de angularjs; (Posibbly jquery). Vous devez appeler $apply pour forcer un cycle $digest . Mais vous ne pouvez pas appeler $apply pendant le cycle de $digest parce que toutes les modifications que vous avez effectuées seront automatiquement reflétées.

Vous devez savoir quand le rappel n'est pas de type angulaire et devrait appeler $apply seulement alors.

Si vous ne savez pas et ne pouvez pas apprendre, voici un truc soigné:

 var applyFn = function () { $scope.someProp = "123"; }; if ($scope.$$phase) { // most of the time it is "$digest" applyFn(); } else { $scope.$apply(applyFn); } 

Comme l'ont souligné Umur Kontacı, vous faites parfois des changements de modèles en dehors du cycle de synthèse. Toutefois, au lieu de contourner ce problème et d'essayer de détecter si vous êtes dans un contexte d'application / digest ou non, je vous suggère de vous assurer que cela n'arrive jamais.

La cause principale de ce problème est que votre fonction est appelée réaction à un événement DOM. Par exemple

 jQuery('.some-element').click(function() { seeminglyProblematicCode() }) 

C'est là que vos $ apply () doivent aller, pas dans la fonction. Sinon, votre code entier sera jalonné de telles distinctions tôt ou tard. En supposant qu'il y ait une portée dans le contexte de ce gestionnaire d'événements, vous pouvez écrire:

 jQuery('.some-element').click(function() { $scope.$apply(function() { seeminglyProblematicCode() }) }) 

Cependant, il y a une mise en garde que vous devez savoir: lorsque vous déclenchez un événement de clic à partir de votre code, vous rencontrerez le problème qu'un cycle de synthèse est déjà en cours. C'est là que vous avez besoin du délai de déchéance. Les réponses à cette question couvrent très bien ce problème.

J'ai eu le même problème, et ma solution était de regarder les contrôleurs appelés dans les directives imbriquées.

 # Parent Controller app.controller 'storeController', ($scope, products) -> $scope.cart = ["chicken", "pizza"] $scope.addToCart = (item) -> $scope.cart.push item # from service products.get().then (items) -> $scope.products = items # Parent Directives app.directive 'storeContainer', ($scope, config) -> restrict: 'E' templatUrl: 'store-container.html' controller: 'storeController' # Nested Directive app.directive 'storeFront', ($scope, config) -> restrict: 'E' templatUrl: 'store-front.html' controller: 'storeController' # Parent Template templates/directives/store-container.html <div ng-repeat="item in cart">{{ item }}</div> <strore-front></store-front> # Nested Template templates/directives/store-front.html <ul ng-repeat="item in products"> <li ng-click"addToCart(item)">{{ item }}</li> </ul> 

Le bug ici est la directive imbriquée qui crée un second contrôleur dans la chaîne prototype (un duplicata de storeController) auquel le modèle parent n'a pas accès. Pour résoudre, écrivez le contrôleur imbriqué de la manière suivante:

 # Nested Directive app.directive 'storeFront', ($scope, config) -> restrict: 'E' templatUrl: 'store-front.html' 

Il existe de meilleures façons de créer la chaîne d'héritage, mais cela va résoudre le problème pour beaucoup de personnes apprenant AngularJS.