AngularJS: $scope.array.push() не обновляет представление даже при использовании $

Я пытаюсь изучить AngularJS, и есть эта вещь, которую я не понимаю, которая кажется, что все интернет решил с помощью $scope.$apply, но я уже использую его, и он ничего не делает.

В принципе, я использую API Twitter для получения временной шкалы, и когда мы прокручиваем снизу, он загружает больше твитов. Эта часть работает, я использую factory, чтобы сделать это, но я могу отобразить прием объекта в консоли, у меня здесь нет проблем.

У меня есть такой вид, чтобы отображать данные:

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

Мой контроллер выглядит следующим образом:

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

достоверны.

То, что я вообще не понимаю, и заставить меня подумать, что это очень легко решить, и я просто не вижу его, заключается в том, что если я использую '= data' вместо 'push (data)' представление обновляется. Даже когда я загружаю больше твитов, если я использую '=', просмотр обновляется (с заменяемым содержимым, конечно, это не то, что я хочу).

Примечание: maxId, fromId и count инициализированы ранее, я не помещал его туда, так как я не думаю, что это важно.

Ответ 1

Проблема заключается в том, что Angular NgRepeat останавливается, если он повторяет один и тот же объект более одного раза. Я создал jsFiddle, чтобы продемонстрировать.

В первом разделе вы можете добавить строки в массив. Первая кнопка всегда добавляет один и тот же строковый объект, а второй создает новый строковый объект каждый раз. Обратите внимание, что как только вы дважды щелкаете по первой кнопке, не важно, что вы добавляете в список.

Во втором разделе мы всегда добавляем новый объект, хотя все эти объекты содержат ссылку на тот же строковый объект. Это работает так, как вы ожидали.

Итак, чтобы сделать это явным ответом, убедитесь, что вещи, которые вы добавляете в свой список, являются отдельными объектами и используют литералы объектов для принудительного применения, если это необходимо. Я бы предпочел Array#push над Array#concat, потому что последний каждый раз создает новый объект массива, и если у вас много предметов, это будет много оттока и много мусора.

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>

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 = [];
        };
    });
})();

Ответ 2

Я считаю, что если вы структурируете свой ng-repeat как таковой (с треком по индексу $index), он не остановится на обманах:

<div class='tweet' ng-repeat='p in posts track by $index'>
...
</div>