Подтвердить что ты не робот

Как использовать дорожку внутри ngFor angular 2

пробовал каждый синтаксис, который я могу догадаться, не смог заставить его работать!

<!--- THIS WORKS FINE --->
<ion-card *ngFor="#post of posts">
{{post|json}}
</ion-card>

<!--- BLANK PAGE --->
<ion-card *ngFor="#post of posts track by post.id">
{{post|json}}
</ion-card>

<!--- Exception : Cannot read property 'id' of undefined --->
<ion-card *ngFor="#post of posts;trackBy:post.id">
{{post|json}}
</ion-card>

<!--- Exception : Cannot read property 'undefined' of undefined --->
<ion-card *ngFor="#post of posts;trackBy:posts[index].id">
{{post|json}}
</ion-card>

<!--- Blank page no exception raised !  --->
<ion-card *ngFor="#post of posts;#index index;trackBy:posts[index].id">
{{post|json}}
</ion-card>

единственный подход, который работал для меня, был

  1. Создание метода в контроллере класса

    определить (индекс, должность: Post) { вернуть post.id }

и

<ion-card *ngFor="#post of posts;trackBy:identify">
</ion-card>

это единственный способ? Могу ли я не просто указать встроенное имя свойства для trackBy?

4b9b3361

Ответ 1

Как указано в комментарии @Eric, и после многих чтений и игр, вот как использовать trackBy в angular2

  • Прежде всего вам нужно знать свой не такой синтаксис, как angular1, теперь вам нужно отделить его от цикла for с помощью ;.

Использование 1: Отслеживание по свойству объекта

 // starting v2. 1 this will throw error, you can only use functions in trackBy from now on

<ion-card *ngFor="let post of posts;trackBy:post?.id">
</ion-card> // **DEPRECATED**
---or---
<ion-card *ngFor="let post of posts;trackBy:trackByFn">
</ion-card>

здесь вы спрашиваете angular2

  • создать локальную запись переменной;
  • вы сообщите trackBy, чтобы ждать, пока эта локальная переменная не будет готова "вы делаете это, используя оператор elvis", знак вопроса после имя переменной ", затем используйте его идентификатор в качестве трекера.

так

// starting v2. 1 this will throw error, you can only use functions in trackBy from now on

*ngFor="#post of posts;trackBy:post?.id"

совпадает с angular 1

ng-repeat="post in posts track by post.id"

Использование 2: Отслеживание с использованием вашей собственной функции

@Page({
    template: `
        <ul>
            <li *ngFor="#post of posts;trackBy:identify">
              {{post.data}}
            </li>
        </ul>
    `
})
export class HomeworkAddStudentsPage {
    posts:Array<{id:number,data:string}>;   

    constructor() {
        this.posts = [  {id:1,data:'post with id 1'},
                        {id:2,data:'post with id 2'} ];
    }

    identify(index,item){
      //do what ever logic you need to come up with the unique identifier of your item in loop, I will just return the object id.
      return post.id 
     }

}

trackBy может принимать имя обратного вызова, и он будет вызывать его для нас, поставляя 2 параметра: индекс цикла и текущий элемент.

Чтобы достичь этого с помощью angular 1, я использовал:

<li ng-repeat="post in posts track by identify($index,post)"></li>

app.controller(function($scope){
  $scope.identify = function(index, item) {return item.id};
});

Ответ 2

Как вы уже узнали, использование функции - единственный способ использовать trackBy в Angular 2

<ion-card *ngFor="#post of posts;trackBy:identify"></ion-card>

В официальной документации указано, что https://angular.io/docs/ts/latest/api/common/index/NgFor-directive.html

Вся остальная информация о <ion-card *ngFor="let post of posts;trackBy:post?.id"></ion-card> неверна. Начиная с Angular 2.4.1 это также вызовет ошибку в приложении.

Ответ 3

Концепция trackBy:

  • ngFor из angular автоматически оптимизирует отображение измененных/созданных/удаленных объектов путем отслеживания идентификатора объекта. Итак, если вы создадите все новые объекты в списке, а затем используйте ngFor, он отобразит весь список.

  • Рассмотрим сценарий, в котором, несмотря на все оптимизации ngFor, рендеринг по-прежнему требует времени. В этом случае мы используем trackBy. Таким образом, мы можем предоставить другой параметр для отслеживания объектов, чем идентификатор объекта, который является критерием отслеживания по умолчанию.

Пример выполнения:

<!DOCTYPE html>
<html>

<head>
    <title>Angular 2.1.2 + TypeScript Starter Kit</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <script src="https://unpkg.com/[email protected]/dist/zone.js"></script>
    <script src="https://unpkg.com/[email protected]/Reflect.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/system.js"></script>
    <script src="https://unpkg.com/[email protected]/lib/typescript.js"></script>
    <script src="config.js"></script>
  <script>
      System.import('app')
          .catch(console.error.bind(console));
    </script>
</head>

<body>
    <my-app>
        loading...
    </my-app>
</body>

</html>

Ответ 4

Просто добавьте несколько примеров (Angular 2+) в дополнение к ответам других, чтобы сделать использование trackBy понятным.

Из документации:

Чтобы избежать этой дорогой операции, вы можете настроить по умолчанию алгоритм отслеживания. предоставив опцию trackBy для NgForOf. trackBy принимает функцию с двумя аргументами: index и item. Если дается trackBy, angular треки изменяются на возвращаемое значение функция.

Подробнее читайте здесь: https://angular.io/api/common/NgForOf

Пример объяснит это лучше.

app.component.ts

   array = [
      { "id": 1, "name": "bill" },
      { "id": 2, "name": "bob" },
      { "id": 3, "name": "billy" }
   ]

   foo() {
      this.array = [
         { "id": 1, "name": "foo" },
         { "id": 2, "name": "bob" },
         { "id": 3, "name": "billy" }
      ]
   }

   identify(index, item) {
      return item.id;
   }

Давайте отобразим array на 3 деления, используя *ngFor.

app.component.html

Пример *ngFor без trackBy:

<div *ngFor="let e of array;">
   {{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>

Что произойдет, если мы нажмем кнопку foo?

→ 3 div будут обновлены. Попробуйте сами, откройте консоль, чтобы проверить.

Пример *ngFor с trackBy:

<div *ngFor="let e of array; trackBy: identify">
   {{e.id}} - {{e.name}}
</div>
<button (click)="foo()">foo</button>

Что произойдет, если мы нажмем кнопку foo?

→ Только первый div будет обновлен. Попробуйте сами, откройте консоль, чтобы проверить.

А что если мы обновим первый объект вместо всего объекта?

   foo() {
      this.array[0].name = "foo";
   }

→ Здесь нет необходимости использовать trackBy.

Это особенно полезно при использовании подписки, которая часто выглядит как то, что я схематизировал с array. Так это будет выглядеть так:

   array = [];
   subscription: Subscription;

   ngOnInit(): void {
      this.subscription = this.fooService.getArray().subscribe(data => {
         this.array = data;
      });
   }

   identify(index, item) {
      return item.id;
   }

Ответ 5

Это простое решение работало для моего сценария

<ion-card *ngFor="let post of posts;let i = index"> 
    {{i+1}}
</ion-card>

РЕДАКТИРОВАТЬ: Как предложил Джереми Тилл ниже, вы должны использовать let вместо #, поскольку # устарел в последних версиях Angular2.