یک نکتهی تکمیلی: روش دیگری برای بهبود کنترل نمایش و مخفی سازی قسمتهای مختلف صفحه
کدهای یک دایرکتیو سفارشی نمایش و یا مخفی سازی قسمتهای مختلف صفحه را بر اساس سطوح دسترسی کاربر جاری، در
IsVisibleForAuthUserDirective مشاهده کردید. روش دیگر انجام اینکار، نوشتن یک دایرکتیو ساختاری شبیه به ngIf توکار خود Angular است. کاری که ngIf انجام میدهد، مخفی کردن یک المان در صفحه نیست؛ بلکه کل آنرا از DOM حذف میکند.
نکتهی اصلی پیاده سازی یک دایرکتیو ساختاری
اگر به سازندهی IsVisibleForAuthUserDirective دقت کنید، تزریق وابستگی ElementRef را داریم:
@Directive({
selector: "[isVisibleForAuthUser]"
})
export class IsVisibleForAuthUserDirective implements OnInit, OnDestroy {
constructor(private elem: ElementRef, private authService: AuthService) { }
به این ترتیب Angular به صورت خودکار امکان دسترسی به المان جاری را با تزریق آن در سازندهی کلاس، میسر میکند.
برای ایجاد یک دایرکتیور ساختاری، نیاز است از تزریق TemplateRef و ViewContainerRef استفاده کرد:
@Directive({
selector: "[hasAuthUserViewPermission]"
})
export class HasAuthUserViewPermissionDirective implements OnInit, OnDestroy {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private authService: AuthService
) { }
در این حالت Angular تنها زمانی این وابستگیها را به سازندهی کلاس تزریق میکند که پیش از نام این دایرکتیو، یک * قرار دهید (مانند ngIf توکار آن):
<div *hasAuthUserViewPermission="['Admin','User']">
*hasAuthUserViewPermission="['Admin','User']"
</div>
پس از آن میتوان از viewContainer، برای نمایش المان و یا قالب مدنظر:
this.viewContainer.createEmbeddedView(this.templateRef);
و یا حذف کامل آن المان از DOM کمک گرفت:
this.viewContainer.clear();
اگر این نکات را کنار هم قرار دهیم و کدهای IsVisibleForAuthUserDirective فوق را بر این اساس اصلاح کنیم،
به قطعه کد زیر میرسیم:
import { Directive, Input, OnDestroy, OnInit, TemplateRef, ViewContainerRef } from "@angular/core";
import { Subscription } from "rxjs/Subscription";
import { AuthService } from "./../../core/services/auth.service";
@Directive({
selector: "[hasAuthUserViewPermission]"
})
export class HasAuthUserViewPermissionDirective implements OnInit, OnDestroy {
private isVisible = false;
private requiredRoles: string[] | null = null;
private subscription: Subscription | null = null;
@Input()
set hasAuthUserViewPermission(roles: string[] | null) {
this.requiredRoles = roles;
}
// Note, if you don't place the * in front, you won't be able to inject the TemplateRef<any> or ViewContainerRef into your directive.
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private authService: AuthService
) { }
ngOnInit() {
this.subscription = this.authService.authStatus$.subscribe(status => this.changeVisibility(status));
this.changeVisibility(this.authService.isAuthUserLoggedIn());
}
ngOnDestroy(): void {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
private changeVisibility(status: boolean) {
const isInRoles = !this.requiredRoles ? true : this.authService.isAuthUserInRoles(this.requiredRoles);
if (isInRoles && status) {
if (!this.isVisible) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.isVisible = true;
}
} else {
this.isVisible = false;
this.viewContainer.clear();
}
}
}
سپس تعریف آنرا به قسمتهای declarations و exports مربوط به
SharedModule اضافه میکنیم:
import { HasAuthUserViewPermissionDirective } from "./directives/has-auth-user-view-permission.directive";
@NgModule({
declarations: [
HasAuthUserViewPermissionDirective
],
exports: [
HasAuthUserViewPermissionDirective
]
})
export class SharedModule {}
اکنون ماژول Dashboard برای استفادهی از این امکانات تنها کافی است SharedModule را دریافت کند (یا هر ماژول دیگری نیز به همین ترتیب است):
import { SharedModule } from "../shared/shared.module";
@NgModule({
imports: [
SharedModule
]
})
export class DashboardModule { }
پس از آن برای مخفی سازی یک المان از دید کاربران وارد نشدهی به سیستم، فقط کافی است دایرکتیو ساختاری hasAuthUserViewPermission را به المان
اعمال کنیم:
<div *hasAuthUserViewPermission="">
*hasAuthUserViewPermission=""
</div>
و یا اگر نیاز به اعمال نقشها نیز وجود داشت میتوان به صورت زیر عمل کرد:
<div *hasAuthUserViewPermission="['Admin','User']">
*hasAuthUserViewPermission="['Admin','User']"
</div>
خلاصهی این تغییرات به کدهای نهایی این سری اعمال شدهاند.