Reputation: 1227
I have a video application written in Angular 4. In this app, user can add a video and subtitles, and edit the videos captions on a list. the captions in list are always synced with the video current play time. When video current time change, the list viewport is changed in order to display the current caption. The number of captions always stay the same, user can not add or remove items only edit the caption text. When having many captions (>500) the app is working very very slowly. I thought about creating and destroying items in the ngFor according to the list viewport, but it seems to be to much work. Is there a better solution (Not using pagging) [![
import { Caption } from './caption';
export class Translation {
public sourceCaption: Caption;
public targetCaption: Caption;
constructor(sourceCaption: Caption, targetCaption: Caption) {
this.sourceCaption = sourceCaption;
this.targetCaption = targetCaption;
}
get startTime() {
return this.sourceCaption && this.sourceCaption.startTime;
}
get endTime() {
return this.sourceCaption && this.sourceCaption.endTime;
}
}
export class Caption{
public startTime: number;
public endTime: number;
public text: Array<string>;
public id: String;
public isFlag: Boolean;
public isItalic: Boolean;
public languageId: String;
public clientId: String;
constructor(clientId: String, languageId: String, id?: String, startTime?: number, endTime?: number, text?: Array<string>, isFlag?:Boolean, isBold?:Boolean, isItalic?: Boolean ) {
this.id = id;
this.clientId = id || clientId;
this.startTime = startTime;
this.endTime = endTime;
this.text = text || new Array<string>();
this.isFlag = isFlag;
this.languageId = languageId;
}
}
<!--list-->
<div class="tt-translations-list">
<tt-translation-list-header></tt-translation-list-header>
<div class="tt-translation-list-items-container" #container>
<div class="tt-translation-list-item-container"
*ngFor="let translation of translations; trackBy:i; let i = index"
(click)="setEditMode(translation)">
<tt-translations-list-item [index]="i"
[translation]="translation">
</tt-translations-list-item>
</div>
</div>
</div>
<!--list-item-->
<div class="tt-translations-list-item"
#container
[ngClass]="{'selected-row': isEditMode}">
<div class="tt-translations-list-item-border-container"
[ngClass]="{'visible': isEditMode}">
</div>
<div class="tt-translations-list-item-source-caption-container">
<div class="source-caption-header">
<tt-translations-list-item-header [caption]="translation.sourceCaption"
[index]="index">
</tt-translations-list-item-header>
</div>
<div class="source-caption-content-container"
dir="auto">
<span *ngFor="let line of translation?.sourceCaption?.text">
{{line}}
</span>
</div>
</div>
<div class="tt-translations-list-item-target-caption-container">
<div class="target-caption-content-container">
<tt-target-caption-editor [editCaption]="translation.targetCaption">
</tt-target-caption-editor>
</div>
</div>
</div>
]2
Upvotes: 2
Views: 2285
Reputation: 2678
I would recommend you to render the list in parts or only the visible captions. If this is not solution for you try to set change detection to
ChangeDetectionStrategy.OnPush
and set the click event on the parent element of the list, to avoid having thousand event clicks (for each row).
If your translations have ID's track by it trackBy: trackByFn
trackByFn(index, item) {
return item.id
}
When you set changedetection OnPush
you have to have always new instance of the array you provide to *ngFor
, for ex:
let captions = [{id: 1, name: '1 caption'}];
// instead of
captions.push({id: 2, name: 'new caption'});
// you have to do
captions = caption.concat({id: 1, name: 'new caption'});
or if you have object, avoid mutating it, because OnPush
works by comparing references of the inputs of the component.
While you did not provide a reference to a new object/array but instead mutated an existing one, the OnPush
change detector did not get triggered.
Upvotes: 1