<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.2.1/rxjs.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/core.js"></script>
<script src="https://unpkg.com/@angular/core@6.0.5/bundles/core.umd.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.26/zone.min.js"></script>
<script src="https://unpkg.com/@angular/http@6.0.5/bundles/http.umd.js"></script>
<script src="https://unpkg.com/@angular/common@6.0.5/bundles/common.umd.js"></script>
<script src="https://unpkg.com/@angular/router@6.0.5/bundles/router.umd.js"></script>
<script src="https://unpkg.com/@angular/compiler@6.0.5/bundles/compiler.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser@6.0.5/bundles/platform-browser.umd.js"></script>
<script src="https://unpkg.com/@angular/platform-browser-dynamic@6.0.5/bundles/platform-browser-dynamic.umd.js"></script>
<script src="https://unpkg.com/@angular/forms@6.0.5/bundles/forms.umd.js"></script>
<my-app></my-app>
// app.js
const { Component, VERSION } = ng.core;
interface Item { id: number; name: string; color: string; }
@Component({
selector: 'my-app',
template: `
<div>
<hr/>
<h3>Without trackBy :( we can't keep focus in the active input box when items (bullets) change as all items are recarated on collection change</h3>
<ul>
<li *ngFor="let item of items; let i = index">
<strong [style.color]="item.color">{{item.id}} | {{item.name}}</strong>
<input size="100%" [value]="values[i]" (input)="values[i] = $event.target.value" >
</li>
</ul>
<hr/>
</div>
<div>
<h3>With trackBy :) focus stays in the active input box even as items (bullets) change. Elements are re-rendered with standard change detection as angular can track elements with their id </h3>
<ul>
<li *ngFor="let itemTrackBy of items; trackBy: trackByFn; let i = index">
<strong [style.color]="itemTrackBy.color" >{{itemTrackBy.id}} | {{itemTrackBy.name}}</strong>
<input size="100%" [value]="values[i]" (input)="values[i] = $event.target.value">
</li>
</ul>
<hr/>
<a target="_blank" href="https://medium.com/simars/improve-ngfor-usability-and-performance-with-trackby-97f32ab92f1c?source=friends_link&sk=7350839886e93f03b360aedcf1577d37">Click Here to read full explanation</a>
</div>
`
})
class AppComponent {
values = ['', '', '']; // values bound to input boxes
items: Item[]; // item to *ngFor without trackby
itemsMock: Item[][]; // Array Mock item array to toggle between
toggle: boolean;
intervalTimer: any;
constructor() {
this.itemsMock = [
[
{id: 1, name: 'One', color: 'red'},
{id: 2, name: 'Two', color: 'blue'},
{id: 3, name: 'Three', color: 'green'}
],
[
{id: 1, name: 'Uno', color: 'blue'},
{id: 2, name: 'Dos', color: 'green'},
{id: 3, name: 'Tres', color: 'red'}
]
];
this.items = this.itemsMock[0];
this.toggle = false;
this.intervalTimer = setInterval(() => {
this.toggleItems();
}, 5000);
}
toggleItems() {
this.toggle = !this.toggle;
this.items = this.toggle ? this.itemsMock[1] : this.itemsMock[0];
}
trackByFn(index, item ) {
console.log( 'TrackBy:', item.id, 'at index', index );
return( item.id );
}
ngOnDestroy(): void {
clearInterval(this.intervalTimer);
}
}
// main.js
const { BrowserModule } = ng.platformBrowser;
const { NgModule } = ng.core;
const { CommonModule } = ng.common;
const { FormsModule } = ng.forms
@NgModule({
imports: [
BrowserModule,
FormsModule,
CommonModule,
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: []
})
class AppModule {}
const { platformBrowserDynamic } = ng.platformBrowserDynamic;
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.