web-dev-qa-db-fra.com

AngularJS: $ scope.array.Push () ne met pas à jour la vue, même avec $ apply

J'essaie d'apprendre AngularJS et il y a cette chose que je ne comprends pas, qui semble être résolue sur Internet en utilisant $scope.$apply, mais je l'utilise déjà et ça ne fait rien.

Fondamentalement, j'utilise l'API Twitter pour récupérer une chronologie, et lorsque nous faisons défiler vers le bas, il charge plus de tweets. Cette partie fonctionne, j'utilise une usine pour le faire, mais je peux afficher l'objet recevoir dans la console, je n'ai pas de problèmes ici.

J'ai une vue comme celle-ci, pour afficher les données:

<div class='timeline' ng-controller='TimelineCtrl' is-scrolled='loadData()'>
    <div class='Tweet' ng-repeat='p in posts'>
        <img class='portrait' src='{{p.user.profile_image_url}}' />
        <p>{{p.text}}</p>
        <p class='date'>{{p.created_at}}</p>
    </div>
</div>

Mon contrôleur ressemble à ceci:

    $scope.posts = [];

    // Load the original tweets list
    TwitterAPI.timeline($scope.count, function(data) {
        $scope.$apply(function() {
            $scope.maxId = data[data.length-1].id;
            $scope.sinceId = data[0].id;
            $scope.posts.Push(data);
        });
    });

les données sont légitimes.

La chose que je ne comprends pas du tout et qui me fait penser que c'est quelque chose de très facile à résoudre et que je ne le vois tout simplement pas, c'est que si j'utilise '= data' au lieu de 'Push (data)', la vue est mis à jour. Même lorsque je charge plus de tweets, si j'utilise '=' la vue est mise à jour (avec le contenu remplacé bien sûr, ce qui n'est pas ce que je veux).

Remarque: maxId, puisqueId et count sont initialisés plus tôt, je ne l'ai pas mis là car je ne pense pas que cela soit important.

12
Mimu

Le problème semble être que NgRepeat d'Angular s'arrête s'il parcourt plus d'une fois le même objet . J'ai créé un jsFiddle pour démontrer.

Dans la première section, vous pouvez ajouter des chaînes à un tableau. Le premier bouton ajoute toujours le même objet chaîne, tandis que le second crée à chaque fois un nouvel objet chaîne. Notez que dès que vous cliquez deux fois sur le premier bouton, peu importe ce que vous ajoutez à la liste.

Dans la deuxième section, nous ajoutons toujours un nouvel objet, même si ces objets contiennent tous une référence au même objet chaîne. Cela fonctionne comme vous vous en doutez.

Donc, pour en faire une réponse explicite, assurez-vous que les éléments que vous ajoutez à votre liste sont des objets distincts , et utilisez des littéraux d'objet pour les appliquer si nécessaire. Je préférerais Array#Push plus de Array#concat parce que ce dernier crée un nouvel objet tableau à chaque fois, et si vous avez beaucoup d'éléments, ce sera beaucoup de désabonnement et beaucoup de garbage collection.

Le HTML:

<div ng-controller="Controller1">
    <button ng-click="addLine()">Add Line</button>
    <button ng-click="addNumber()">Add Number</button>
    <button ng-click="reset()">Reset</button>
    <div>{{lines}}</div>
    <div ng-repeat="line in lines">
        {{line}}
    </div>
</div>

<hr />

<div ng-controller="Controller2">
    <button ng-click="addObject()">Add Object</button>
    <button ng-click="reset()">Reset</button>
    <div>{{objects}}</div>
    <div ng-repeat="obj in objects">
        {{obj.data}}
    </div>
</div>

Le JavaScript:

(function () {
    var myApp = angular.module('myApp', []);

    myApp.controller('Controller1', function ($scope) {
        $scope.lines = [];

        $scope.addLine = function () {
            $scope.lines.Push('Hello world!');
        };

        $scope.addNumber = function () {
            $scope.lines.Push('Line ' + $scope.lines.length);
        };

        $scope.reset = function () {
            $scope.lines = [];
        };
    });

    myApp.controller('Controller2', function ($scope) {
        $scope.objects = [];

        $scope.addObject = function () {
            var obj = { data: 'Hello world!' };
            $scope.objects.Push(obj);
        };

        $scope.reset = function () {
            $scope.objects = [];
        };
    });
})();
10
Chris Bouchard

Je crois que si vous structurez votre ng-repeat comme tel (avec piste par $ index), cela ne s'arrêtera pas sur les dupes:

<div class='Tweet' ng-repeat='p in posts track by $index'>
...
</div>
6
Geoff Oslund