Reputation: 1438
I use an attribute by control access to check if a field should be enabled or disabled.
So i have something like this :
<input matInput type="text" #name="ngModel" name="application.name" [ngModel]="application?.name" (ngModelChange)="application.name=$event"
placeholder="Nom de l'application" required [disabled]="isDisabled([permissions.applications.any.update, permissions.applications.own.update], 'name')"[appUnique]="application" [listElem]="applications" key="name" maxlength="255">
The isDisabled
function is called hundreds times when the input is displayed and each action on the form triggers something like 12 or 32 additional calls.
That causes my browser to freeze.
Any idea why this behavior is occuring? Is it ZoneJS which cause this?
How can make just one called to this function?
Edit: Directive implementation
/**
* Check if the component should be disabled
*/
@Directive({
selector: "[appIsDisabled]"
})
export class IsDisabledDirective implements OnInit {
// Listof permission to check
@Input("appIsDisabled") permissions: PermissionInterface[];
// The resource id to be access
@Input() resourceId: number;
// The resource type to be access
@Input() resourceType: string;
// Attribute to be check(eg: name, firstname... for a user resource)
@Input() attribute: string;
constructor(private authService: AuthService, private el: ElementRef, private utilsService: UtilsService, private renderer: Renderer2) {
}
ngOnInit() {
if (!this.authService.hasPermission(this.permissions, this.resourceId, this.resourceType, this.attribute)) {
this.renderer.setAttribute(this.el.nativeElement, "disabled", "disabled");
}
}
}
Upvotes: 0
Views: 92
Reputation: 1438
OK, i found a solution to my problem, I pre-calculate the state off all fields in the component side. So for a user profile this is my function :
computesFieldsDisableState() {
this.disabled = {
thumbnails: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "thumbnails"),
name: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "name"),
firstname: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "firstname"),
password: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "password"),
email: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "email"),
roles: !this.authService.hasPermission([this.permissions.profil.update], this.user.id, "user", "roles"),
};
}
Now i just have to use [disabled]="disabled.thumbnails"
to get the state of the field.
Thank you all for you answers.
Upvotes: 0
Reputation: 12619
The short answer is your method is executed by angular in changes detection algorithm. Angular scans every binding to detect changes and act accordingly and it does it fairly often and it can happen many times per single event. You need to learn about this process and how to minimize it. This is a big subject and going into details in SO answer is not appropriate, but three tips from the referenced article are:
Have less DOM. This is a critically important piece of the puzzle. If DOM elements aren’t visible, you should remove them from the DOM by using *ngIf instead of simply hiding elements with CSS. As the saying goes, the fastest code is code that is not run—and the fastest DOM is DOM that doesn’t exist.
Make your expressions faster. Move complex calculations into the ngDoCheck lifecycle hook, and refer to the calculated value in your view. Cache results to complex calculations as long as possible.
Use the OnPush change detection strategy to tell Angular 2 there have been no changes. This lets you skip the entire change detection step on most of your application most of the time.
Upvotes: 0
Reputation: 3626
You better not doing property binding to a method to avoid too frequently checking status.
Here are my suggestions:
ngOnInit
hook in your component.isDisabled
method to a pure pipe component.Upvotes: 1