Angular UI Carousel 的`track by $index` 问题 [英] Problems with `track by $index` with Angular UI Carousel

查看:23
本文介绍了Angular UI Carousel 的`track by $index` 问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

.filter('pages', function () {返回函数(输入,当前页面,页面大小){如果(angular.isArray(输入)){var start = (currentPage - 1) * pageSize;var end = currentPage * pageSize;返回 input.slice(start, end);}};})

控制器:

self.currentPage = 1;self.itemsPerPage = 500;self.maxSize = 10;//imagesUrls 是来自 http 调用的 response.dataangular.forEach(imagesUrls,函数(父){var date = uibDateParser.parse(parent.fileCreationTime, 'M/d/yyyyhh:mm:ss a');//用 url 填充我们的幻灯片数组//这里更新模型self.slides.push({图像:parent.fileName,时间:日期,id:parent.id});});self.totalItems = self.slides.length;

我是这样使用的:

<div uib-slide ng-repeat="slide in $ctrl.slides |页数:$ctrl.currentPage : $ctrl.itemsPerPage 按 $index 跟踪index=$index"><img id="carousel-img";ng-src={{slide.image}}"><div class="carousel-caption"><p>索引{{$index}}</p>

<div class="row"><ul uib-分页total-items=$ctrl.totalItems";items-per-page="$ctrl.itemsPerPage";ng-model="$ctrl.currentPage";最大尺寸=$ctrl.maxSize";边界链接编号=真";force-ellipses="true"class=分页-sm">

这按预期工作.

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

问题:

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

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

如果你滑动到索引20,然后点击分页链接,索引仍然是20.当你显示当前图像的幻灯片id时,它变成了520.

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

我希望我的问题很清楚.

解决方案

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

 

<div class="carousel-caption"><p>索引{{̶$̶i̶n̶d̶e̶x̶slide.id}}</p>

来自文档:

<块引用><块引用>

如果您正在处理具有唯一标识符属性的对象,则应通过此标识符而不是对象实例进行跟踪.如果您稍后重新加载数据,ngRepeat 将不必为它已经呈现的项目重建 DOM 元素,即使集合中的 JavaScript 对象已被新对象替换.对于大型集合,这会显着提高渲染性能.

—AngularJS ng-repeat 指令 API 参考 - 跟踪

演示

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 (让 i=0; i<40; i++) {var 幻灯片 = {文件名:url+"?image="+(1000+i),id: 'id'+(0+i+100),文件创建时间:新日期()}imagesUrls.push(slide);}self.slides = [];//imagesUrls 是来自 http 调用的 response.dataangular.forEach(imagesUrls,函数(父){var date = uibDateParser.parse(parent.fileCreationTime,'M/d/yyyy hh:mm:ss a');//用 url 填充我们的幻灯片数组//这里更新模型self.slides.push({图像:parent.fileName,时间:日期,id:parent.id});});//console.log(self.slides);self.totalItems = self.slides.length;}).filter('页面', 函数 () {返回函数(输入,当前页面,页面大小){如果(angular.isArray(输入)){var start = (currentPage - 1) * pageSize;var end = currentPage * pageSize;返回 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-carouselactive="$ctrl.active"间隔=$ctrl.myInterval"no-wrap="$ctrl.noWrapSlides"无暂停=真"><div uib-slide ng-repeat="slide in $ctrl.slides | pages:$ctrl.currentPage : $ctrl.itemsPerPage 通过 slide.id 跟踪"index="$index"><img id="{{slide.id}}" ng-src="{{slide.image}}"><div class="carousel-caption"><p>索引{{slide.id}}</p>

<div class="行容器"><ul uib-分页total-items="$ctrl.totalItems"items-per-page="$ctrl.itemsPerPage"ng-model="$ctrl.currentPage"最大尺寸="$ctrl.maxSize"边界链接编号=真"强制省略号 =真"class="分页-sm">

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

解决方案

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>

这篇关于Angular UI Carousel 的`track by $index` 问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆