do not run change detection in extensible system components with using abp permission directive

pull/13147/head
muhammedaltug 3 years ago
parent 5be7ec73c7
commit 2921c869da

@ -136,6 +136,7 @@ export class CoreModule {
return {
ngModule: RootCoreModule,
providers: [
OAuthModule.forRoot().providers,
LocaleProvider,
CookieLanguageProvider,
{
@ -190,7 +191,6 @@ export class CoreModule {
useValue: localizationContributor(options.localizations),
deps: [LocalizationService],
},
OAuthModule.forRoot().providers,
],
};
}

@ -18,6 +18,8 @@ import { PermissionService } from '../services/permission.service';
export class PermissionDirective implements OnDestroy, OnChanges {
@Input('abpPermission') condition: string | undefined;
@Input('abpPermissionRunChangeDetection') runChangeDetection = true;
subscription!: Subscription;
constructor(
@ -38,7 +40,11 @@ export class PermissionDirective implements OnDestroy, OnChanges {
.subscribe(isGranted => {
this.vcRef.clear();
if (isGranted) this.vcRef.createEmbeddedView(this.templateRef);
this.cdRef.detectChanges();
if (this.runChangeDetection) {
this.cdRef.detectChanges();
} else {
this.cdRef.markForCheck();
}
});
}

@ -2,10 +2,12 @@ import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/je
import { Subject } from 'rxjs';
import { PermissionDirective } from '../directives/permission.directive';
import { PermissionService } from '../services';
import { ChangeDetectorRef } from '@angular/core';
describe('PermissionDirective', () => {
let spectator: SpectatorDirective<PermissionDirective>;
let directive: PermissionDirective;
let cdr: ChangeDetectorRef;
const grantedPolicy$ = new Subject<boolean>();
const createDirective = createDirectiveFactory({
directive: PermissionDirective,
@ -30,7 +32,7 @@ describe('PermissionDirective', () => {
grantedPolicy$.next(true);
expect(spectator.query('#test-element')).toBeTruthy();
grantedPolicy$.next(false);
// expect(spectator.query('#test-element')).toBeFalsy(); // TODO: change detection problem should be fixed
expect(spectator.query('#test-element')).toBeFalsy();
});
});
@ -41,6 +43,7 @@ describe('PermissionDirective', () => {
{ hostProps: { condition: '' } },
);
directive = spectator.directive;
cdr = (directive as any).cdRef as ChangeDetectorRef;
});
it('should be created', () => {
@ -55,8 +58,22 @@ describe('PermissionDirective', () => {
grantedPolicy$.next(false);
expect(spectator.query('#test-element')).toBeFalsy();
grantedPolicy$.next(true);
expect(spectator.queryAll('#test-element')).toHaveLength(1);
});
it('should call detect changes method', () => {
const detectChanges = jest.spyOn(cdr, 'detectChanges');
expect(spectator.query('#test-element')).toBeFalsy();
spectator.setHostInput({ condition: 'test' });
grantedPolicy$.next(true);
expect(spectator.query('#test-element')).toBeTruthy();
expect(detectChanges).toHaveBeenCalled();
grantedPolicy$.next(false);
expect(spectator.query('#test-element')).toBeFalsy();
expect(detectChanges).toHaveBeenCalled();
grantedPolicy$.next(true);
expect(spectator.queryAll('#test-element')).toHaveLength(1);
expect(detectChanges).toHaveBeenCalled();
});
describe('#subscription', () => {
@ -70,4 +87,35 @@ describe('PermissionDirective', () => {
});
});
});
describe('with runChangeDetection Input', () => {
beforeEach(() => {
spectator = createDirective(
'<div id="test-element" *abpPermission="condition;runChangeDetection:false">Testing Permission Directive</div>',
{ hostProps: { condition: '' } },
);
directive = spectator.directive;
cdr = (directive as any).cdRef as ChangeDetectorRef;
});
it('should not call detectChanges method', () => {
const detectChanges = jest.spyOn(cdr, 'detectChanges');
const markForCheck = jest.spyOn(cdr, 'markForCheck');
expect(spectator.query('#test-element')).toBeFalsy();
spectator.setHostInput({ condition: 'test' });
grantedPolicy$.next(true);
expect(spectator.query('#test-element')).toBeTruthy();
expect(detectChanges).not.toHaveBeenCalled();
expect(markForCheck).toHaveBeenCalled();
grantedPolicy$.next(false);
expect(spectator.query('#test-element')).toBeFalsy();
expect(detectChanges).not.toHaveBeenCalled();
expect(markForCheck).toHaveBeenCalled();
grantedPolicy$.next(true);
expect(spectator.queryAll('#test-element')).toHaveLength(1);
expect(detectChanges).not.toHaveBeenCalled();
expect(markForCheck).toHaveBeenCalled();
});
});
});

@ -1,4 +1,8 @@
<div class="mb-3 form-group" *abpPermission="prop.permission" [ngSwitch]="getComponent(prop)">
<div
class="mb-3 form-group"
*abpPermission="prop.permission; runChangeDetection: false"
[ngSwitch]="getComponent(prop)"
>
<ng-template ngSwitchCase="input">
<ng-template [ngTemplateOutlet]="label"></ng-template>
<input

@ -24,7 +24,7 @@
[sortable]="prop.sortable"
>
<ng-template let-row="row" let-i="index" ngx-datatable-cell-template>
<ng-container *abpPermission="prop.permission">
<ng-container *abpPermission="prop.permission; runChangeDetection: false">
<ng-container *ngIf="row['_' + prop.name]?.visible">
<div
*ngIf="!row['_' + prop.name].component; else component"

@ -27,7 +27,7 @@
<ng-container *ngIf="action.visible(data)">
<button
ngbDropdownItem
*abpPermission="action.permission"
*abpPermission="action.permission; runChangeDetection: false"
(click)="action.action(data)"
type="button"
>
@ -49,7 +49,7 @@
<ng-template #btnTmp let-action>
<ng-container *ngIf="action.visible(data)">
<button
*abpPermission="action.permission"
*abpPermission="action.permission; runChangeDetection: false"
(click)="action.action(data)"
type="button"
class="btn btn-primary text-center"

@ -5,7 +5,7 @@
*ngFor="let action of actionList; trackBy: trackByFn; let last = last"
>
<ng-container *ngIf="action.visible(data)">
<ng-container *abpPermission="action.permission">
<ng-container *abpPermission="action.permission;runChangeDetection: false">
<ng-container *ngIf="action.component as component; else button">
<ng-container
*ngComponentOutlet="component; injector: record | createInjector: action:this"
@ -13,7 +13,11 @@
</ng-container>
<ng-template #button>
<button (click)="action.action(data)" type="button" [ngClass]="action.btnClass ? action.btnClass : defaultBtnClass" >
<button
(click)="action.action(data)"
type="button"
[ngClass]="action.btnClass ? action.btnClass : defaultBtnClass"
>
<i [ngClass]="action.icon" [class.me-1]="action.icon"></i>
{{ action.text | abpLocalization }}
</button>

Loading…
Cancel
Save