角度2。如何在检查访问后隐藏(不呈现)菜单中的 link?
Angular2. How to hide(no-render) the link in the menu after check access?
检查ACL访问后,需要根据"routerLink"在菜单中隐藏link。我不想在应用程序中的每个元素 link 上使用 angular 指令 "*ngIf"(需要在 routerConfig 定义中全局执行)
内容可以在组件上使用注解@CanActivate控制,但需要在菜单中隐藏link
我尝试使用覆盖 "routerLink" 指令来做到这一点,但是在这个指令中覆盖后无法访问我定义的扩展参数(资源和特权)路由器配置
示例:
@Component({})
@RouteConfig([{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
data: {'resource':'account', 'privilage':'show'}
}])
但无法访问 "routerLink" 中的此配置数据 (routerData)。
知道怎么做吗?
第二个版本
多级菜单和从 routerConfig 定义访问(扩展数据配置)仍然有问题。
主要成分
@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 {
}
用户组件
@RouteConfig([
{ path: '/profile', name: 'ProfileLink', component: ProfileComponent, data: {res: 'user', priv: 'details'} },
])
@Component({ ... })
export class UserComponent {
}
配置文件组件
@Component({ ... })
export class ProfileComponent {
}
我的安全指令
@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']);
}
}
此解决方案仅适用于菜单的子项,不适用于主级菜单,并且不确定该解决方案是否适用于多级菜单。
我尝试不同的方法来解决这个问题我尝试访问指令中的 RouterConfig 定义(和我的 routerData 扩展配置)并使用 通过 link 的别名检查元素@Input('routerLink') 但找不到如何访问 RouterConfig。
当路由在 angular2 中激活时,它默认添加 .router-link-active
class 到 link.
所以我会hide
或disable
激活路由,
@Component({
selector: 'my-app',
// to hide it,
styles: [".router-link-active { Display: none;}"], //just add it in single line...
// to hide it,
styles: [".router-link-active { pointer-events: none;cursor: default;opacity: 0.6; }"], //just add it in single line...
template:'...'
)}
我认为您可以创建一个专门的指令来执行此操作。该指令将附加到包含 routerLink
的同一 HTML 元素上。这样您就可以访问本机元素和 RouterLink
指令:
@Directive({
selector: '[secured]'
})
export class Secured {
constructor(private routerLink:RouterLink,private eltRef:ElementRef) {
(...)
}
}
并这样使用它:
@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 ...
基于RouterLink
指令实例,您可以访问定义路由时指定的数据,并在必要时隐藏元素:
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);
}
(...)
}
参见 src/app.ts
中的 this plunkr
编辑
如 the issue by Brandon 中所建议,我们可以从 routerLink
属性中指定的值重新生成组件指令:
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);
}
(...)
}
检查ACL访问后,需要根据"routerLink"在菜单中隐藏link。我不想在应用程序中的每个元素 link 上使用 angular 指令 "*ngIf"(需要在 routerConfig 定义中全局执行)
内容可以在组件上使用注解@CanActivate控制,但需要在菜单中隐藏link
我尝试使用覆盖 "routerLink" 指令来做到这一点,但是在这个指令中覆盖后无法访问我定义的扩展参数(资源和特权)路由器配置
示例:
@Component({})
@RouteConfig([{
path: '/dashboard',
name: 'Dashboard',
component: DashboardComponent,
data: {'resource':'account', 'privilage':'show'}
}])
但无法访问 "routerLink" 中的此配置数据 (routerData)。
知道怎么做吗?
第二个版本
多级菜单和从 routerConfig 定义访问(扩展数据配置)仍然有问题。
主要成分
@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 {
}
用户组件
@RouteConfig([
{ path: '/profile', name: 'ProfileLink', component: ProfileComponent, data: {res: 'user', priv: 'details'} },
])
@Component({ ... })
export class UserComponent {
}
配置文件组件
@Component({ ... })
export class ProfileComponent {
}
我的安全指令
@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']);
}
}
此解决方案仅适用于菜单的子项,不适用于主级菜单,并且不确定该解决方案是否适用于多级菜单。
我尝试不同的方法来解决这个问题我尝试访问指令中的 RouterConfig 定义(和我的 routerData 扩展配置)并使用 通过 link 的别名检查元素@Input('routerLink') 但找不到如何访问 RouterConfig。
当路由在 angular2 中激活时,它默认添加 .router-link-active
class 到 link.
所以我会hide
或disable
激活路由,
@Component({
selector: 'my-app',
// to hide it,
styles: [".router-link-active { Display: none;}"], //just add it in single line...
// to hide it,
styles: [".router-link-active { pointer-events: none;cursor: default;opacity: 0.6; }"], //just add it in single line...
template:'...'
)}
我认为您可以创建一个专门的指令来执行此操作。该指令将附加到包含 routerLink
的同一 HTML 元素上。这样您就可以访问本机元素和 RouterLink
指令:
@Directive({
selector: '[secured]'
})
export class Secured {
constructor(private routerLink:RouterLink,private eltRef:ElementRef) {
(...)
}
}
并这样使用它:
@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 ...
基于RouterLink
指令实例,您可以访问定义路由时指定的数据,并在必要时隐藏元素:
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);
}
(...)
}
参见 src/app.ts
编辑
如 the issue by Brandon 中所建议,我们可以从 routerLink
属性中指定的值重新生成组件指令:
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);
}
(...)
}