Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.6k views
in Technique[技术] by (71.8m points)

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

$index in track by index does not start at zero when pagination is used

I have created a carousel using angular ui bootsrap. Since am loading so many images(over 1,000), I used a filter to display 500 pictures in the pagination.

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

The controller:

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;

And I use it like this:

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

This works as expected.

When the carousel is first loaded, the index is 0. When it moves to the next slide the index is 1, when you move to the next slide the index is 2. When you display the slide.id of the current image it is also 2.

The problem:

However, when you click the second pagination link, the index does not go back to zero, its starts at the last index the slide was in the carousel.

So now the index is 2 and slide id of the current image is 502.

If you slide till index 20, and you click the pagination link, the index is still at 20. When you display the slide id of the current image it becomes 520.

Is there a way to make the index start at 0 again so the slide.id is 500 and not 502 or 520?

I hope my question is clear.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Avoid track by $index when there is a unique property identifier to work with. When working with objects that are all unique (as is this case), it is better to let ng-repeat to use its own tracking instead of overriding with 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>

From the Docs:

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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...