1

I have a component which is basically a list of items, where each item contains a name and a row of boxes. Something like this (but styled): John Doe [1][2][3][4][5] Each box represents a task, each task is either "approved" or "not approved". If it's approved it's green, if not then grey. The data for each item is passed through from a Element object which also has an array of Task objects as one of its values and each box is attached to a (click) listener which toggles the value of task.approved and the color of the box, accordingly.

The problem arises when there are a lot of items in the list. I tested it with 90 items and each time I click on a box it takes up to 300ms to change its color.

I tried a lot of different ways of rectifying this, here is the first iteration of the HTML:

<md-list>
      <md-list-item *ngFor="let item of testData" class="flex-container">
          <div style="margin-left:10px;"> {{item.firstName + " " + item.lastName}}</div>
          
          <div class="boxes">
              <div *ngFor="let task of item.tasks;"  style="cursor: pointer;" >
                  <div *NgIf="task.approved" class="flex-item box" style="background-color: green;" (click)="task.approved = !task.approved">{{task.taskNumber}}</div>
                  <div *NgIf="!task.approved" class="flex-item box" style="background-color: lightgrey;" (click)="task.approved = !task.approved">{{task.taskNumber}}</div>
              </div>
          </div>            
      </md-list-item>
</md-list>

TS:

export class App {
  testData: Element[];
  
  constructor() { }

  ngOnInit() {
    this.testData = [];
    for(var i=0; i<90; i++) {
      this.testData.push({
        id: i,
        firstName: "John" + (i + 1),
        lastName: "Doe",
        tasks: Task[],
      });
      for(var t=0; t<10; t++) {
        this.testData[i].tasks.push(
          {
            taskNumber: t+1,
            approved: (t%2 == 0) ? true: false //for variation sake
          }
        );
      }
      
    }
  }
}

export interface Element {
  id: number;
  firstName: string;
  lastName: string;
  tasks: Task[];
}

export interface Task {
  taskNumber: number;
  approved: boolean;
}

After this I tried:

  • changing the Detection Strategy to onPush.
  • adding a button which adds the listeners to the according row after you click it
  • having only one listener and using the information from $event.target
  • using pure CSS for handling click events and changing the color with this hack: Can I have an onclick effect in CSS?

None of these made a noticeable improvement on the performance. I could also restrict the number of list items, but surely there is a different way of doing this.

aframestor
  • 176
  • 6
  • try trackBy on both ngFor – Alexander Sep 22 '17 at 15:29
  • I already have. Not entirely sure what it does, but I didn't notice a difference in performance. – aframestor Sep 22 '17 at 15:30
  • I pasted your code into the default Material 2 plunker http://plnkr.co/edit/vQT0RcnztDK8yiortvf9?p=preview and the toggling (dont mind the layout) works instantly Btw typo in tasks: Task[], -> tasks: [] – Alexander Sep 22 '17 at 15:40
  • Have you tried modifying CSS instead of re-rendering the element? [ngClass](https://angular.io/api/common/NgClass); [ngStyle](https://angular.io/api/common/NgStyle) – Marian Sep 22 '17 at 15:40
  • @Alexander hmm would the lack of CSS affect things? I also have a sidenav in my program and a few other elements – aframestor Sep 22 '17 at 15:44
  • Depends on what is in that CSS/other components. I suggest you disable those components and then enable one by one. – Alexander Sep 22 '17 at 15:50
  • @Alexander I ran your code on my machine and it's still slow. Plunker's servers are probably a lot more powerful than what I'm running on. – aframestor Sep 22 '17 at 16:39
  • Did you ever figure this out? @aframestor – Garuuk Feb 13 '18 at 21:33
  • 1
    @Garuuk I ended up having a separate pop up for approving tasks, and generating the html for the boxes in the component instead of dynamically in the template. – aframestor Apr 04 '18 at 21:34

0 Answers0