Pretty standard situation.
There is one parent component <item-list>
.
Inside its template with *ngFor
generated 20 child components <item-block>
.
Child component styles set with [ngStyle]
directive and template expression that calls function setStyles()
.
The problem (or maybe not) is that when any event emitted on one specific child element, expression setStyles()
executed twice for each of child components.
So if we click on one specific item in our example, and we have 20 <item-block>
components - setStyles()
will be executed 20+20 times.
The questions are:
Example & plnkr:
plnkr (click on item - open console for debug output)
import {Component} from '@angular/core'
@Component({
selector: 'item-list',
template: `
<item-block
[item]="item"
*ngFor="let item of items"
></item-block>
`,
})
export class ItemListComponent {
items: any[] = [];
constructor() {}
ngOnInit() {
// generate dummy empty items
for (let i = 0; i < 20; i++) {
this.items.push(
{
value: 'item #' + i;
}
)
}
}
}
import {Component, Input} from '@angular/core'
@Component({
selector: 'item-block',
template: `
<div
class="item"
[ngStyle]="setStyles()"
(click)="testClick($event)"
>{{item.value}}</div>
`,
})
export class ItemBlockComponent {
@Input() item: any;
constructor() {}
testClick(): void{
console.log('item clicked');
}
setStyles(){
console.log('seting styles...');
return {
'background': '#ccc'
};
}
}
[ngStyle]="setStyles()"
causes setStyles
to be called every time change detection is run (which can be quite often and will hurt performance). Also because setStyles()
returns a different object instance every time, it should cause an exception. "Expression changed since it was last checked" or similar.
Calling methods from the view this way is discouraged.
Instead assign the value to a property and bind to that property:
[ngStyle]="myStyles"
In default (development mode) Angular run Detect Changes mechanism twice.
In production mode it is reduce to single change.
In main.ts
file try to add:
import { enableProdMode } from '@angular/core';
// ...
enableProdMode();
// ...
platformBrowserDynamic().bootstrapModule(AppModule)
and reload application.
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