Angular UI Carousel 的 `track by $index` 问题

Problems with `track by $index` with Angular UI Carousel

使用分页时,按索引跟踪的 $index 不从零开始

我使用 angular ui bootsrap 创建了一个旋转木马。 由于加载了这么多图片(超过1,000张),我使用过滤器在分页中显示了500张图片。

.filter('pages', function () {
    return function (input, currentPage, pageSize) {
        if (angular.isArray(input)) {
            var start = (currentPage - 1) * pageSize;
            var end = currentPage * pageSize;
            return input.slice(start, end);
        }
    };
})

控制器:

self.currentPage = 1;
self.itemsPerPage = 500;
self.maxSize = 10;

//imagesUrls is response.data from http call
angular.forEach(imagesUrls, function (parent) {
    var date = uibDateParser.parse(parent.fileCreationTime, 'M/d/yyyy 
                     hh:mm:ss a');
    // fill our slide arrays with urls
    // model update here
    self.slides.push({
        image: parent.fileName,
        time: date,
        id: parent.id
    });      
});
self.totalItems = self.slides.length;

我是这样使用的:

<div uib-carousel 
     active="$ctrl.active"
     interval="$ctrl.myInterval"
     no-wrap="$ctrl.noWrapSlides"
     no-pause="true">
     <div uib-slide ng-repeat="slide in $ctrl.slides | pages: 
              $ctrl.currentPage : $ctrl.itemsPerPage track by $index" 
          index="$index">
         <img id="carousel-img" ng-src="{{slide.image}}">
         <div class="carousel-caption">
             <p>Index {{$index}}</p>
         </div>
     </div>
 </div>

<div class="row">
    <ul uib-pagination
        total-items="$ctrl.totalItems"
        items-per-page="$ctrl.itemsPerPage"
        ng-model="$ctrl.currentPage"
        max-size="$ctrl.maxSize"
        boundary-link-numbers="true"
        force-ellipses="true"
        class="pagination-sm">
    </ul>
 </div>

这按预期工作。

首次加载轮播时,索引为0。移动到下一张幻灯片时,索引为1,移动到下一张幻灯片时,索引为2。 当你显示当前图片的slide.id也是2.

问题:

但是,当您单击第二个分页 link 时,索引不会归零,而是从幻灯片在轮播中的最后一个索引开始。

所以现在索引为2,当前图像的幻灯片ID为502。

如果滑动到index 20,点击分页link,index还是20,显示当前图片的slide id时变成520。

有没有办法让索引再次从 0 开始,以便 slide.id 是 500 而不是 502 或 520?

我希望我的问题很清楚。

当有唯一的 属性 标识符可供使用时,请避免使用 track by $index。当处理所有唯一的对象时(如本例),最好让 ng-repeat 使用自己的跟踪而不是用 track by $index.

覆盖
 <div uib-slide ng-repeat="slide in $ctrl.slides | pages: 
          $ctrl.currentPage : $ctrl.itemsPerPage track by  ̶$̶i̶n̶d̶e̶x̶ slide.id" 
      index="$index">
     <img id="{{slide.id}}" ng-src="{{slide.image}}">
     <div class="carousel-caption">
         <p>Index {{ ̶$̶i̶n̶d̶e̶x̶ slide.id}}</p>
     </div>
 </div>

来自文档:

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

The DEMO

angular.module("app",['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.controller("ctrl", function(uibDateParser) {
  var self = this;
self.currentPage = 1;
self.itemsPerPage = 10;
self.maxSize = 10;

var url = '//unsplash.it/200/100';
var imagesUrls = [];
for (let i=0; i<40; i++) {
  var slide = {
    fileName: url+"?image="+(1000+i),
    id: 'id'+(0+i+100),
    fileCreationTime: new Date()
  }
  imagesUrls.push(slide); 
}
self.slides = [];

//imagesUrls is response.data from http call
angular.forEach(imagesUrls, function (parent) {
    var date = uibDateParser.parse(parent.fileCreationTime,
        'M/d/yyyy hh:mm:ss a');
    // fill our slide arrays with urls
    // model update here
    self.slides.push({
        image: parent.fileName,
        time: date,
        id: parent.id
    });      
});
//console.log(self.slides);
self.totalItems = self.slides.length;
})
.filter('pages', function () {
    return function (input, currentPage, pageSize) {
        if (angular.isArray(input)) {
            var start = (currentPage - 1) * pageSize;
            var end = currentPage * pageSize;
            return input.slice(start, end);
        }
    };
})
    <script src="//unpkg.com/angular/angular.js"></script>
    <script src="//unpkg.com/angular-animate/angular-animate.js"></script>
    <script src="//unpkg.com/angular-sanitize/angular-sanitize.js"></script>
    <script src="//unpkg.com/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js"></script>    
    <link href="//unpkg.com/bootstrap/dist/css/bootstrap.css" rel="stylesheet">

  <body ng-app="app" ng-controller="ctrl as $ctrl">
    <div class="container" uib-carousel 
     active="$ctrl.active"
     interval="$ctrl.myInterval"
     no-wrap="$ctrl.noWrapSlides"
     no-pause="true">
     <div uib-slide ng-repeat="slide in $ctrl.slides | pages: 
              $ctrl.currentPage : $ctrl.itemsPerPage track by slide.id" 
          index="$index">
         <img id="{{slide.id}}" ng-src="{{slide.image}}">
         <div class="carousel-caption">
             <p>Index {{slide.id}}</p>
         </div>
     </div>
 </div>

<div class="row container">
    <ul uib-pagination
        total-items="$ctrl.totalItems"
        items-per-page="$ctrl.itemsPerPage"
        ng-model="$ctrl.currentPage"
        max-size="$ctrl.maxSize"
        boundary-link-numbers="true"
        force-ellipses="true"
        class="pagination-sm">
    </ul>
 </div>
  </body>