In this article we are going to learn how to create a Role-Based Show/Hide Directive in Angular. If you are in the Angular realm for a good long time, you must be familiar with the concept of directives. Directives are one of the basic building blocks of Angular. It is everywhere. Even components in Angular are in directives with a template.
Directives basically are typescript classes with
@Directive decorators. From the Angular documentation, you can see there are three types of directives
- Components: directives with a template.
- Structural directives: change the DOM layout by adding and removing DOM elements.
- Attribute directives: change the appearance or behavior of an element, component, or another directive.
Some common directives that must be familiar to you are:
NgStyle(attribute), etc. The scope of this article will be on the last type: Attribute directives.
Recently on one of my projects, I had a requirement for a simple role-based access system. In one of my modules, the add, edit, delete, or update actions were based on the user role which is determined at the admin level and is configurable. The access information is available on the user login.
How would you implement this?
Initial thoughts were to use
[hidden] directives in all components with custom logic inside the component’s controller. It looked easy to implement. But how reusable would it be? What if you want to use it in multiple modules, components? Yes, time to introduce a directive!
Create a Custom Angular Directive
Like I stated above, directives are typescript classes. You can create a file, conveniently name it
access-control.directive.ts and create your class manually. But I am going to take help from Angular CLI to do this.
ng generate directive access-control
You now have the simplest directive ever, which doesn’t do anything just yet.
import Directive from "@angular/core"; @Directive( selector: "[accessControl]", ) export class AccessControlDirective constructor()
Before we jump in and start editing our directive, let’s have a look at our access control data that we received from our REST API.
"access_controls": [ "module_name": "users", "create_action": false, "read_action": true, "update_action": true, "delete_action": false , "module_name": "articles", "create_action": true, "read_action": true, "update_action": false, "delete_action": false ]
From the data above, it is evident that our directive needs to get at least two pieces of information from the host, (the component where the directive is used):
- Type of module (users or articles)
- Type of access (create, edit, delete, or read)
Let’s take a step back and recall that components are indeed directives, thus you can pass data to a directive the same way as you do to a component. We can use a
@Input decorator. We also need to implement
NgOnInit in our directive for us to be able to check access controls on the initialization of the component.
import Directive, Input, OnInit from "@angular/core"; @Directive( selector: "[accessControl]", ) export class AccessControlDirective implements OnInit @Input("moduleType") moduleType: string; @Input("accessType") accessType: string; constructor() ngOnInit()
Great! Let’s implement our logic to conditionally show/hide the host element, (the component our directive is hosted on).
import Directive, Input, OnInit, ElementRef from "@angular/core"; import AuthService from "./auth.service"; @Directive( selector: "[accessControl]", ) export class AccessControlDirective implements OnInit @Input("moduleType") moduleType: string; @Input("accessType") accessType: string; constructor(private elementRef: ElementRef, private auth: AuthService) ngOnInit() this.elementRef.nativeElement.style.display = "none"; this.checkAccess(); checkAccess() const accessControls: any = this.auth.getAccessControls(); const module: any = accessControls.find(access => access.module_name === this.moduleType); this.elementRef.nativeElement.style.display = module[this.accessType] ? "block" : "none";
We have imported
@angular/core which we can use to access DOM elements and manipulate. Be careful when you use
ElementRef, as you are accessing DOM elements directly, which can attract XSS attacks. On the component initialization, we are fetching role data, crosschecking with our module and access type combination, and making the element show/hide.
Note: I am fetching the access data from the
AuthService class which is an Angular service I created. You can have your custom login to do the same.
Let’s now see how we can use this in one of our components.
As easy as that! The button above will now show/hide based on the user access controls. You can use our
accessControl directive in any of the create, edit, delete, read navigation buttons/components. It’s highly reusable.
There are plenty of other use cases for directives. You can do things like listening for events on the host and reacting to the same, apply styles to the host, and more. I hope you will create something beautiful with it.