Need to hide link in menu based on the "routerLink" after check ACL access. I do not want to use angular directives "*ngIf" on each element link in app (need to do that globaly on the routerConfig definition)
Content can controll using annotation @CanActivate on components but need to hide link in menu
I try do that with overwrite "routerLink" directive, but in this directives after overwrite can't get access to my extends param defined(resources and privilages) in routerConfig
Example:
@Component({})
@RouteConfig([{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
data: {'resource':'account', 'privilage':'show'}
}])
But can't get access to this config data(routerData) in the "routerLink".
Some idea how can do that?
Second version
Multi level menu and stiil have problem with get access to the (extend data config) from routerConfig definition.
Main component
@RouteConfig([
{ path:'/dashboard', name: 'DashboardLink', component: DashboardComponent, data: { res: 'dasboard', priv: 'show'}, useAsDefault: true },
{ path:'/user/...', name: 'UserLink', component: UserComponent, data: { res: 'user', priv: 'show'} },
])
@Component({
selector: 'main-app',
template: `
<ul class="left-menu">
<li><a secured [routerLink]="['UserLink']">User</a>
<ul>
<li><a secured [routerLink]="['ProfileLink']">Profile</a></li>
</ul>
</li>
<li><a secured [routerLink]="['HomeLink']">Home</a></li>
<li><a secured [routerLink]="['DashboardLink']">Dashboard</a></li>
</ul>
<router-outlet></router-outlet>
`
})
export class MainComponent {
}
User component
@RouteConfig([
{ path: '/profile', name: 'ProfileLink', component: ProfileComponent, data: {res: 'user', priv: 'details'} },
])
@Component({ ... })
export class UserComponent {
}
Profile component
@Component({ ... })
export class ProfileComponent {
}
My secure directives
@Directive({
selector: '[secured]'
})
export class SecuredDirective {
@Input('routerLink')
routeParams: any[];
/**
*
*/
constructor(private _viewContainer: ViewContainerRef, private _elementRef: ElementRef, private router:Router) {
}
ngAfterViewInit(){
//Get access to the directives element router instructions (with parent instructions)
let instruction = this.router.generate(this.routeParams);
//Find last child element od instruction - I thing thats my component but I am not sure (work good with two levels of menu)
this.getRouterChild(instruction);
}
private getRouterChild(obj: any){
var obj1 = obj;
while(true) {
if( typeof obj1.child !== 'undefined' && obj1.child !== null ){
obj1 = obj1.child;
} else {
break;
}
}
this.checkResPrivAcl(obj1.component.routeData.data)
}
private checkResPrivAcl(aclResAndPriv: any){
let hasAccess = CommonAclService.getInstance().hasAccess(aclResAndPriv['res'], aclResAndPriv['priv']);
if (!hasAccess) {
let el : HTMLElement = this._elementRef.nativeElement;
el.parentNode.removeChild(el);
}
console.log("CHECK ACL: " + aclResAndPriv['res'] + " | " + aclResAndPriv['priv']);
}
}
This solution work only for child item of menu don't work with the main level of menu, and not sure is this work correctly on the multi level menu.
I try diffrent way to resolve this problem I try get access to the RouterConfig definition (and my routerData extend config) in the directives and check element by the alias name of link using @Input('routerLink') but don't find how can I get access to the RouterConfig.
I think that you could create a dedicated directive to do that. This directive would be attach on the same HTML element that contains the routerLink
one. This way you would have access to both native element and RouterLink
directive:
@Directive({
selector: '[secured]'
})
export class Secured {
constructor(private routerLink:RouterLink,private eltRef:ElementRef) {
(...)
}
}
and use it this way:
@Component({
selector: 'app',
template: `
<router-outlet></router-outlet>
<a secured [routerLink]="['./Home']">Home</a>
`,
providers: [ ROUTER_PROVIDERS ],
directives: [ ROUTER_DIRECTIVES, Secured ],
pipes: []
})
@RouteConfig([
{
path: '/home',
name: 'Home',
component: HomeComponent,
useAsDefault: true,
data: {'resources':'account', 'privilages':'show'}
},
(...)
])
export class ...
Based on the RouterLink
directive instance, you can have access to the data you specified when defining the route and hide the element if necessary:
export class Secured {
@HostBinding('hidden')
hideRouterLink:boolean;
constructor(private routerLink:RouterLink) {
}
ngAfterViewInit()
var data = this.routerLink._navigationInstruction.component.routeData.data;
this.hideRouterLink = this.shouldBeHidden(data);
}
(...)
}
See this plunkr in the src/app.ts
Edit
As suggested in the issue by Brandon, we could regenerate the component instruction from the value specified in the routerLink
attribute:
export class Secured {
@HostBinding('hidden')
hideRouterLink:boolean;
@Input('routerLink')
routeParams:string;
constructor(private router:Router) {
}
ngAfterViewInit() {
var instruction = this.router.generate(this.routeParams);
var data = instruction.component.routeData.data;
this.hideRouterLink = this.shouldBeHidden(data);
}
(...)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With