I have an extreme need not to rebuild the DOM for an array of values, each of which holds an object representing a YouTube livestream. I am using ngFor to iterate out the livestreams.
However, when the livestreams change (this could be because the user wants to alter the viewing order, so the livestream they want to watch the most is on top - see reorder()
below), ngFor rebuilds the elements, which causes YouTube embeds to be removed from the DOM, and reinserted; which results in the running livestreams to stop playing, and also reloads them - which takes a second or so. This is not optimal.
I have tried to use trackBy
to follow the values by the name of the livestream (a property in my object) rather than the object itself, but this does not appear to have resolved the issue.
Template:
<livestream-player *ngFor="let livestream of userPrefs.visibleLivestreams(); trackBy: livestreamTrackByFn" [video]="livestream.url | sanitize:'resource'">
</livestream-player>
Array of elements: userPrefs.visibleLivestreams()
public visibleLivestreams() : Livestream[] {
let livestreams = [
{ name: 'a', url: 'youtubeUrl', ... },
{ name: 'b', url: 'youtubeUrl', ... },
{ name: 'c', url: 'youtubeUrl', ... }
];
// _visibleLivestreams, used below to order and filter,
// is a simple, ordered, array of strings representing
// the livestream names, stored in localstorage.
return livestreams
.filter(l => this._visibleLivestreams.indexOf(l.name) != -1);
.sort((a, b) => this._visibleLivestreams.indexOf(a.name) < this._visibleLivestreams.indexOf(b.name) ? -1 : 1);
}
Not-working trackBy functionality used in *ngFor template
public livestreamTrackByFn(index: number, item: Livestream) : string {
return item.name;
}
Reorder functionality
/**
* Reorders elements of the livestreams array by shifting off the
* 0th element, and pushing it the last position in the array.
*
* Calling this function results in the DOM being rebuilt!
*/
public rotate() : void {
// shift element off _visibleLivestreams
let elem = this.userPrefs.visibleLivestreams.shift();
// push element onto _visibleStreams
this.userPrefs.visibleLivestreams.push(elem);
}
As the above implementation rebuilds the DOM unnecessarily, I'm really looking for a workaround for this problem. My thoughts so far are creating a custom *ngFor
-like structural directive, using flexbox to manage the order, or simply identifying a small change in my existing implementation which resolves this issue.