Angular 中的对象数组中未触发 detectChanges()

detectChanges() not fired in object array in Angular

*ngFor 由于迭代了数千行,使我的应用程序非常慢。它按预期工作,但性能较慢。如果更改 select 或输入值,其值将显示为红色。如果 _main.rolls 被迭代,我能够获取所有修改的值并将它们发送到 API 进行更新。

<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>         

*我做了一些修改。首先找到一个索引并显示该项目。它足够快,但不会存储更改。我只能通过 _main.rolls 数组更改一项。它不是对所有值都触发的 detectChages() 。还有一个问题。如果 select 或输入的值发生变化,该值仍然是黑色而不是红色。

<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>         

在 .ts 文件中。

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)
    }
  }

我不是经验丰富的 Angular 程序员。我的方法可能是错误的,是否有更好的方法来解决我的代码中的性能问题?

是的,有更好的方法。您的两个解决方案都需要嵌套迭代,您可以通过迭代 rolls 并创建一个对象来避免这种情况,其中键是学生 ID,值是卷。对象使您可以即时访问,因此您不必在模板中对其进行迭代。你可以做这样的事情来构建这个 'map':

studentRollsMap = {};
this._main.rolls.forEach(roll => {
    studentRollsMap[roll.student_id] = roll;
})

然后在您的模板中您可以遍历 students,同时能够绑定到 studentRollsMap[student.id]

根据您的评论,这应该可以将性能提高 5 到 10 倍

我能感觉到你的紧张,我希望我的话能提供信息,帮助你找到最好的解决办法。

我认为一个好的解决方案是在 class 文件而不是模板文件中执行所有条件样式 classes。使用 .map() 遍历数据数组并向数组中的每个对象添加两个新属性,一个用于 <td> class roll.email_sent_datetime?'table-cell-attendance-code-emailed' : 'table-cell-attendance-code'" 另一个用于 <input>风格class_main.rolls[_index].email_sent_datetime?'table-cell-attendance-note-emailed' : 'table-cell-attendance-note'".

我相信使用这种方式可以将调整样式所用的时间缩短为零并且可以触摸。

更重要的是,您可以遍历整个可靠的数据数组 _main.students_main.attendance_dates_main.rolls,这样您就只能在 [=18 中使用一个数据数组=] [也在 class.ts 文件中]