Angular: 使用新数据更新 $scope 会导致旧数据在使用 ng-repeat 时保留

Angular: Updating $scope with new data causes old data to remain when using ng-repeat

我遇到了一个奇怪的问题,我用新数据替换了 $rootScope.data.vehicles 中的值,但我视图中的旧数据点与新数据一起保留了大约一秒钟。

例如,在我用新数组替换 $rootScope.data.vehicles 数组后,我的视图将首先显示 3 个新值,然后显示 3 个旧值。视图在 $rootScope.data.vehicles 上使用 ng-repeat 来显示图块。

大约一秒钟后,视图中不再显示 3 个旧值。

每次触发间隔时,我都会得到新值和旧值,即使这些值没有改变。

我的控制器和工厂是这样的:

(function () {
    var vehiclesInjectParams = ['$location', 'dataService', '$rootScope', 'VehiclesRefreshService'];

    var VehiclesController = function ($location, dataService, $rootScope, VehiclesRefreshService) {
        var vm = this;

        if ($rootScope.data == undefined)
            $rootScope.data = {};

        $rootScope.data.vehicles = [];

        function init() {
            dataService.getVehicles()
                .then(function (data) {
                    $rootScope.data.vehicles = data.results;
                }, function (error) {
                    var thisError = error.data.message;
                });

            VehiclesRefreshService.getValues();
        };

        init();
    };

    VehiclesController.$inject = vehiclesInjectParams;

    var vehiclesRefreshInjectParams = ['$interval', '$rootScope', '$q', 'dataService'];

    var VehiclesRefreshService = function ($interval, $rootScope, $q, dataService) {
        var factory = {};

        factory.getValues = function () {
            var interval = $interval(function () {
                dataService.getVehicles()
                .then(function (data) {
                    $rootScope.data.vehicles = data.results;
                }, function (error) {
                    var thisError = error.data.message;
                });
            }, 10000);

        };

        return factory;
    };

    VehiclesRefreshService.$inject = vehiclesRefreshInjectParams;

    angular.module('teleAiDiagnostics').controller('VehiclesController', VehiclesController).factory('VehiclesRefreshService', VehiclesRefreshService);
}());

首先加载数组,然后启动 $interval 计时器每 10 秒刷新一次值。一旦 dataService returns 新的值列表并将它们放入 $rootScope.data.vehicles 中,我注意到有六个图块而不是 3 个。一秒钟之后,我只剩下 3 个新图块。

我的观点是这样的:

<header>
    <h1>Vehicles</h1>
</header>

<article class="icon-gallery flexslider">
    <section>
        <figure ng-repeat="vehicle in $parent.data.vehicles" class="gallery-item svg">
            <a class="nextpage" ng-href="#!/vehicle/{{vehicle.vehicleID}}">
                <img src="img/machine/01.svg" alt="">
                <span class="green-machine-code">{{vehicle.id}}</span>
            </a>
            <ul>
                <li>{{vehicle.id}}</li>
                <li>{{vehicle.ip}}</li>
                <li>Online: {{vehicle.online}}</li>
                <li>Status: {{vehicle.status}}</li>
                <li>AllClear: {{vehicle.allClear}}</li>
            </ul>
        </figure>
    </section>
</article>

关于如何让我的磁贴无缝刷新有什么想法吗?非常感谢所有帮助。

Mike Feltman 在上面的评论中解决了这个问题。就像将 'track by $index' 添加到视图中的 ng-repeat 标记一样简单。看这里:

<header>
    <h1>Vehicles</h1>
</header>

<article class="icon-gallery flexslider">
    <section>
        <figure ng-repeat="vehicle in $parent.data.vehicles track by $index" class="gallery-item svg">
            <a class="nextpage" ng-href="#!/vehicle/{{vehicle.vehicleID}}">
                <img src="img/machine/01.svg" alt="">
                <span class="green-machine-code">{{vehicle.id}}</span>
            </a>
            <ul>
                <li>{{vehicle.id}}</li>
                <li>{{vehicle.ip}}</li>
                <li>Online: {{vehicle.online}}</li>
                <li>Status: {{vehicle.status}}</li>
                <li>AllClear: {{vehicle.allClear}}</li>
            </ul>
        </figure>
    </section>
</article>

希望这篇 post 能对以后遇到相同类型问题的人有所帮助。

IIRC,在内部 Angular 看到车辆数组已更改并立即渲染它,然后清理。通过 $index 添加 track 到 ng-repeat 应该基本上每次都强制渲染从第一个项目开始。

我同意其他 post 关于 $rootScope 的使用。如果您试图让车辆在全球范围内可用而不是将它们存储在 rootScope 中,请将它们存储在您的数据服务中并在必要时注入它。这将是一种更简洁的方法。

当有唯一的 属性 标识符可以使用时,避免 track by $index

<figure ng-repeat="vehicle in $parent.data.vehicles track by ̲v̲e̲h̲i̲c̲l̲e̲.̲i̲d̲ ̶$̶i̶n̶d̶e̶x̶" class="gallery-item svg">
    <a class="nextpage" ng-href="#!/vehicle/{{vehicle.vehicleID}}">
        <img src="img/machine/01.svg" alt="">
        <span class="green-machine-code">{{vehicle.id}}</span>
    </a>
    <ul>
        <li>{{vehicle.id}}</li>
        <li>{{vehicle.ip}}</li>
        <li>Online: {{vehicle.online}}</li>
        <li>Status: {{vehicle.status}}</li>
        <li>AllClear: {{vehicle.allClear}}</li>
    </ul>
</figure>

来自文档:

If you are working with objects that have a unique identifier property, you should track by this identifier instead of the object instance. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance.

— AngularJS ng-repeat Directive API Reference - Tracking