Reputation: 2455
I have a simple list that needs to have one of its items selected on click. However, every x seconds the list "refreshes", and the selection seems to get lost.
To add the selection back to the newly created element, I introduced setTimeout, but that seems to have a "flashing" effect.
setInterval( () => {
this.locations.forEach((o, i, a) => a[i] = a[i] + 's'); // update locations
setTimeout(() => {
if (this.selectedLocationID) document.getElementById(this.selectedLocationID).classList.add('selectedLocation');
}, 0);
}, 1000);
How to prevent the "flashing" as seen in the plunk?
Upvotes: 1
Views: 601
Reputation: 40
Here you go buddy
//our root app component
import {Component, NgModule, VERSION} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
@Component({
selector: 'my-app',
template: `
<h3> Select an item </h3>
<div *ngFor="let location of locations; let i=index;">
<div [ngClass]="{'selectedLocation':selectedLocation==i}">
<li (click)="selectLocation(i)">Hello {{location}}</li>
</div>
</div>
`
})
export class App {
selectedLocation;
locations: Array = ["World", "Mars", "Saturn", "Pluto"];
constructor() {
// datasource updates every sec
setInterval( () => {
this.locations.forEach((o, i, a) => a[i] = a[i] + 's'); // update locations
// if (this.selectedLocationID) document.getElementById(this.selectedLocationID).classList.add('selectedLocation');
setTimeout(() => {
//if (this.selectedLocationID) document.getElementById(this.selectedLocationID).classList.add('selectedLocation');
}, 0);
}, 1000);
}
selectLocation(i) {
this.selectedLocation = i;
}
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App ],
bootstrap: [ App ]
})
export class AppModule {}
Upvotes: 1
Reputation: 343
Every time this runs:
this.locations.forEach((o, i, a) => a[i] = a[i] + 's'); // update locations
the *ngFor
completely re-draws the HTML from scratch, removing the class you added on the click:
<div *ngFor="let location of locations; let i = index;">
<li id="location-{{i}}" (click)="selectLocation($event.target.id)">Hello {{location}}</li>
</div>
The trick is to ensure this class, if set, remains on the re-draw. Something like this (full solution here: https://plnkr.co/edit/6PTWU6dpQLSa5c3tVDbg):
<div *ngFor="let location of locations; let i = index;">
<li id="location-{{i}}" (click)="selectLocation($event.target.id, i)" [ngClass]="{selectedLocation: selectedLocationIndex == i}">Hello {{location}}</li>
</div>
Rather than tracking the HTML element ID, my solution just tracks the index of the *ngFor
loop, which we were already tracking with let i = index
(passing $event.target.id
is no longer required, but won't hurt anything).
We then use [ngClass]
to set/remove the 'selectedLocation' class if the index of our loop, i
, matches the index of the selected item that we are now tracking with selectedLocationIndex
.
Upvotes: 1