Как использовать дорожку внутри 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>
единственный подход, который работал для меня, был
Создание метода в контроллере класса
определить (индекс, должность: Post) { вернуть post.id
}
и
<ion-card *ngFor="#post of posts;trackBy:identify">
</ion-card>
это единственный способ? Могу ли я не просто указать встроенное имя свойства для trackBy?
Ответы
Ответ 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.