How do I get Angular 2/4 to update existing DOM no

2019-04-12 15:50发布

My Angular 4 application has a Component that has a refresh method that pulls-in a large object from my web-service, like so:

DTOs/Model types:

class NuclearReactorStatus {

    public reactorName: string;
    public coolingRods: CoolingRodStatus[]; // array of 1024 elements
}

class CoolingRodStatus {
    public rodId      : number;
    public temperature: number;
    public status     : string;
}

Inside the NuclearReactorDisplayComponent:

public reactorStatus: NuclearReactorStatus;

refresh(): void {

    this.http.get<NuclearReactorStatus>()
        .subscribe(
            status => {
                this.reactorStatus = status;
            },
            err => {
                console.error( err );
            }
        );
}

Inside my nuclearreactordisplay.component.html

<h1>Reactor {{reactorStatus.reactorName}}</h1>

<h2>Cooling rods</h2>
<ol *ngIf="reactorStatus.coolingRods">
    <li *ngFor="let rod of reactorStatus.coolingRods"
        [data.rod-id]="rod.rodId"
        [data.rod-temperature]="rod.temperature"
        class="{{ rod.temperature < 100 ? "cool" : rod.temperature < 1000 ? "warm" : rod.temperature < 10000 ? "hot" : "jalapeno" }}"
    >
        <span>{{rod.rodId}}</span>
    </li>
</ol>

I'm styling the rod <li> elements by arranging them into a grid:

ol {
    display: flex;
    flex-wrap: wrap;
    list-style: none;
    width: calc( 32 * 16px ); // grid is 32 elements wide, 32x32 == 1024
}
li {
    display: block;
    width: 16px;
    height: 16px;

    transition: background-color 0.2s;
}
li span {
    display: none;
}

li.cool     { background-color: black; }
li.warm     { background-color: orange; }
li.hot      { background-color: yellow; }
li.jalapeno { background-color: red; }

Note my use of transition: background-color so the rod's box's background color changes gradually instead of suddenly.

When I run my program, I notice that Angular actually replaces the <ol> and all child <li> elements each time the data refreshes instead of using the existing DOM and updating the class attributes - so my background-color transition never happens - but more alarmingly the CPU usage on my computer skyrockets because of the expense of manipulating the DOM this way.

How do I get Angular to re-use the <ol> and <li> elements it created in the template instead of deleting and recreating them on every refresh cycle?

1条回答
萌系小妹纸
2楼-- · 2019-04-12 16:21

Since ngFor may preform bad when the data list is huge, Angular has provided a trackBy which you can tell angular how to replace existing DOM elements. See details here.

<ol *ngIf="reactorStatus.coolingRods">
  <li *ngFor="let rod of reactorStatus.coolingRods; trackBy: trackByFun"
    [data.rod-id]="rod.rodId"
    [data.rod-temperature]="rod.temperature" class="{{ rod.temperature < 100 ? "cool" : rod.temperature < 1000 ? "warm" : rod.temperature < 10000 ? "hot" : "jalapeno" }}">
    <span>{{rod.rodId}}</span>
  </li>
</ol>

TrackByFun:

// assume you want to regenerate DOM element when rodId changed.
trackByFun(index: number, rod) { 
  return rod.rodId;               
}
查看更多
登录 后发表回答