I'm generating two lists for a roster
.
One list to show the current members of that year
, and a second list if people have been excused in that year
.
I noticed that I have two of the same for loops except one prints out all of the true Boolean values, and one the false. Is there a better way (or a method of some sort) to print out the people who are excused and not excused
?
<h2>Roster {{year-1}}-{{year}}</h2>
<div *ngFor="let k of peoples">
<div *ngFor="let a of k.people; let j = index">
<div *ngIf="k.year == year && k.people[j].excused == false">
{{k.people[j].firstName}} {{k.people[j].lastName}}
</div>
</div>
</div>
<h2>Excused</h2>
<div *ngFor="let k of peoples">
<div *ngFor="let a of k.people; let j = index">
<div *ngIf="k.year == year && k.people[j].excused == true">
{{k.people[j].firstName}} {{k.people[j].lastName}}
</div>
</div>
</div>
'For' loops are considered obsolete, hence we should avoid using them. In single threaded languages like JavaScript, the 'for' loop acts as a thread blocker, which hinders the scalability of a system.
When not to use them? If you want to swap elements of an array, if you want to reverse order. You can't even increment the values by 1 and store them back into the array, because for that, you would need to know their corresponding key.
The for-each loop should generally be preferred. The "get" approach may be slower if the List implementation you are using does not support random access. For example, if a LinkedList is used, you would incur a traversal cost, whereas the for-each approach uses an iterator that keeps track of its position in the list.
Comparing performance , map() wins! map() works way faster than for loop. Considering the same code above when run in this ide.
It would be better to use it this way without additional *ngIf.
As mentioned in comments it would be better to prepare to separete arrays for data in the component and do it once after data updated. But since the context of usage is unknown this looks like a better solution. You need to avoid *ngIf if you can filter data in array to prevent from unnecessary work another structure directive in template. It always gives you perfomance advanateges.
In your component you can define filter function
:
getExcused(isExcused: boolean) {
return this.peoples
.filter(k=>k.year === this.year)
.map(k=>k.people)
.filter(p=>p.excused === isExcused);
}
Then in template:
<h2>Roster {{year-1}}-{{year}}</h2>
<div *ngFor="let a of getExcused(false)">
{{ a.firstName }} {{ a.lastName }}
</div>
<h2>Excused</h2>
<div *ngFor="let k of getExcused(true)">
{{ k.firstName }} {{ k.lastName }}
</div>
If your component uses change detection strategy on push it won't make any perfomance issues.
Maybe I'am wrong, but isn't a pipe the prefered way of doing this ? Or better, you could chain 2 pipes !
<div *ngFor="let k of peoples| yearPipe: year | excusedPipe: no">
{{k.people[j].firstName}} {{k.people[j].lastName}}
</div>
<h2>Excused</h2>
<div *ngFor="let k of peoples| yearPipe: year | excusedPipe: yes">
{{k.people[j].firstName}} {{k.people[j].lastName}}
</div>
@Pipe({ name: 'yearPipe' })
export class YearPipe implements PipeTransform {
transform(allPeople: People[], year: string) {
return allPeople.filter(person => person.year == parseInt(year));
}
}
@Pipe({ name: 'excusedPipe' })
export class ExcusedPipe implements PipeTransform {
transform(allPeople: People[], excused: string) {
if (excused === 'yes'){
return allPeople.filter(person => person.excused);
}else{
return allPeople.filter(person => !person.excused);
}
}
}
The only tricky part is that the parameter to the pipe is allways string, or that is what I find in docs in Angular.io
Edit : refer to this stackblitz example ( Chained Pipes example ): https://stackblitz.com/edit/angular-rb5vmu
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With