*ngFor makes my app extremely slow due to thousand rows iterated. It works as expected except for slow performance. If the select or input value is changed, its value will be in red. If the _main.rolls is iterated, I am able to fetch all values modified and send them to API to update.
<tr *ngFor="let student of _main.students"> <!-- up to 250 students (rows). -->
<ng-container *ngFor="let date of _main.attendance_dates"> <!-- up to 5 school days (rows) in the same week. -->
<ng-container *ngFor="let roll of _main.rolls"> <!-- up to 5 days (rows) times 250 students per two columns (5*250*2) in the same week. -->
<ng-container *ngIf="student.id == roll.student_id && date.date == roll.date">
<td [ngClass] = "roll.email_sent_datetime?'table-cell-attendance-code-emailed' : 'table-cell-attendance-code'">
<select [(ngModel)]="roll.attendance_type_seq_new" [ngClass]="roll.attendance_type_seq == roll.attendance_type_seq_new ? 'select-attendance-type' : 'select-attendance-type-changed'">
<option [value]="0" >Not selected</option>
<option *ngFor="let answer of _main.attendance_tyes" [value]="answer.seq">
{{answer.description}}
</option>
</select>
</td>
<td [ngClass] = "roll.email_sent_datetime?'table-cell-attendance-note-emailed' : 'table-cell-attendance-note'">
<input [(ngModel)]="roll.attendance_note_new" placeholder="" title="{{roll.attendance_note_new}}" [ngClass]="roll.attendance_note == roll.attendance_note_new ? 'input-attendance-note' : 'input-attendance-note-changed'"/>
</td>
</ng-container>
</ng-container>
</ng-container>
</tr>
*I made some changes. Find an index first and display the item. It is faster enough but the changes are not stored. I can get only one item changed through _main.rolls array. It is not detectChages() fired on all values. There is another problem too. If the value of the select or input is changed, the value is still in black not in red.
<tr *ngFor="let student of _main.students"> <!-- up to 250 students (rows). -->
<ng-container *ngFor="let date of _main.attendance_dates"> <!-- up to 5 school days (rows) in the same week. -->
{{getRollSelectedIndex(student.id, date.date)}} <!-- fetch the index of the row in the rolls. -->
<!-- <ng-container *ngFor="let roll of _main.rolls"> up to 5 days (rows) times 250 students per two columns (5*250*2) in the same week. -->
<ng-container *ngIf="_index">
<td [ngClass] = "_main.rolls[_index].email_sent_datetime?'table-cell-attendance-code-emailed' : 'table-cell-attendance-code'">
<select [(ngModel)]="_main.rolls[_index].attendance_type_seq_new" [ngClass]="_main.rolls[_index].attendance_type_seq == _main.rolls[_index].attendance_type_seq_new ? 'select-attendance-type' : 'select-attendance-type-changed'">
<option [value]="0" >Not selected</option>
<option *ngFor="let answer of _main.attendance_tyes" [value]="answer.seq">
{{answer.description}}
</option>
</select>
</td>
<td [ngClass] = "_main.rolls[_index].email_sent_datetime?'table-cell-attendance-note-emailed' : 'table-cell-attendance-note'">
<input [(ngModel)]="_main.rolls[_index].attendance_note_new" placeholder="" title="{{_main.rolls[_index].attendance_note_new}}" [ngClass]="_main.rolls[_index].attendance_note == _main.rolls[_index].attendance_note_new ? 'input-attendance-note' : 'input-attendance-note-changed'"/>
</td>
</ng-container>
<!-- </ng-container> -->
</ng-container>
</tr>
In .ts file.
getRollSelectedIndex(student_id: number, date: Date){
if (this._main.rolls != null )
{
this._index = this._main.rolls.findIndex(x=>x.student_id === student_id && x.attendance_date === date)
}
}
I am not an experienced Angular programmer. My approach could be wrong and is there a better way to tackle the performance issue in my code?
Yes, there's a better way. Both of your solutions required nested iterations, which you can avoid by iterating over rolls
and creating an object where the keys are the student id's and the value is the roll. Objects give you instant access, so you don't have to iterate over it in the template. You could do something like this to build this 'map':
studentRollsMap = {};
this._main.rolls.forEach(roll => {
studentRollsMap[roll.student_id] = roll;
})
Then in your template you can iterate over students
and at the same time be able to bind to studentRollsMap[student.id]
This should improve performance by 5 to 10 times according to your comments