In this tutorial we will see how to Display or View Component Based on User Role In Angular 9. Not just a component also it can be applied to every element of the HTML.
In any application with multiple user roles, you might face a scenario to show and hide the component or an element in the DOM to handle such a scenario we can create a directive like a *ngIf
so let’s create it.
Topics
View Component Based on User Role
lets first understand how our directive will work with the templates.
An application can be based on single or multiple user roles. so the directive will accept an array property in which multiple user roles can be defined.
<!-- Display only for Admin -->
<app-some-component *ifRoles='["Admin"]'> ... </app-some-component>
<!-- Display only for Admin & SuperAdmin -->
<app-some-component *ifRoles='["Admin", "SuperAdmin"]'> ... </app-some-component>
<!-- *ifRoles : using on HTML Elements -->
<section *ifRoles='["User"]'> ... </section>
How user role directive will work
- If the user has the proper role as mention in the directive selector then the component should be added in DOM.
- In case if the user is not having the proper role to view specific content then that component or an element should be removed from the DOM.
It will behave similarly to *ngIf='true'
or *ngIf='false'
we use in angular.
User Role Service
For roles, we must have a service that gets us a user role list. To demonstrate I have used the www.jsonbin.io site to store some static data to make a demo work.
https://api.jsonbin.io/b/5eca9addbbaf1f2589463bbf - (Dummy API for USer Roles)
{
"roles": [
"Admin",
"SuperAdmin",
"User",
"DataManager"
]
}
Directive To Show and Hide Based on User Roles
let’s first generate a directive using angular CLI command
ng generate directive IfRoles
and our directive will have something like this.
import { Input, OnInit, Directive, ViewContainerRef, TemplateRef, OnDestroy } from "@angular/core";
import { Subject, Subscription } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { RolesService } from "../services/roles.service";
@Directive({
selector: '[ifRoles]'
})
export class IfRolesDirective implements OnInit, OnDestroy {
private subscription: Subscription[] = [];
// the role the user must have
@Input() public ifRoles: Array<string>;
/**
* @param {ViewContainerRef} viewContainerRef -- the location where we need to render the templateRef
* @param {TemplateRef<any>} templateRef -- the templateRef to be potentially rendered
* @param {RolesService} rolesService -- will give us access to the roles a user has
*/
constructor(
private viewContainerRef: ViewContainerRef,
private templateRef: TemplateRef<any>,
private rolesService: RolesService
) {}
public ngOnInit(): void {
this.subscription.push(
this.rolesService.roles().subscribe(res => {
if (!res.roles) {
// Remove element from DOM
this.viewContainerRef.clear();
}
// user Role are checked by a Roles mention in DOM
const idx = res.roles.findIndex((element) => this.ifRoles.indexOf(element) !== -1);
if (idx < 0) {
this.viewContainerRef.clear();
} else {
// appends the ref element to DOM
this.viewContainerRef.createEmbeddedView(this.templateRef);
}
})
);
}
/**
* on destroy cancels the API if its fetching.
*/
public ngOnDestroy(): void {
this.subscription.forEach((subscription: Subscription) => subscription.unsubscribe());
}
}
this.templateRef
contains the DOM refrence inside theifRoles
selector.viewContainerRef.clear()
will remove the content from the DOM if the user Roles is not matched.viewContainerRef.createEmbeddedView(templateRef)
Will Append the DOM if the user roles is matched.