Угловой2. Как скрыть(не отображать) ссылку в меню после проверки доступа?

Необходимо скрыть ссылку в меню на основе "routerLink" после проверки доступа ACL. Я не хочу использовать угловые директивы "*ngIf" для каждой ссылки на элемент в приложении (необходимо сделать это глобально в определении routerConfig)

Контентом можно управлять с помощью аннотации @CanActivate на компонентах, но необходимо скрыть ссылку в меню

Я пытаюсь сделать это с помощью директивы "routerLink", но в этой директиве после перезаписи не удается получить доступ к моему параметру расширения, определенному (ресурсы и привилегии) ​​в routerConfig.

Пример:

@Component({})
@RouteConfig([{   
    path: '/dashboard', 
    name: 'Dashboard', 
    component: DashboardComponent, 
    data: {'resource':'account', 'privilage':'show'} 
}])

Но не могу получить доступ к этим данным конфигурации (routerData) в «routerLink».

Некоторая идея, как это сделать?

Вторая версия

Многоуровневое меню и stiil имеют проблемы с получением доступа к (расширенной конфигурации данных) из определения 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) в директивах и проверить элемент по псевдониму ссылки, используя @Input('routerLink') но не нашел, как мне получить доступ к RouterConfig.


person Power Web Design    schedule 16.03.2016    source источник
comment
Я не понимаю, что такое check access?   -  person micronyks    schedule 16.03.2016
comment
Я имею в виду проверку доступа, имеет ли посетитель право на ссылку - ресурс, определенный в данных: {'resource':'account', 'privilage':'show'}   -  person Power Web Design    schedule 16.03.2016


Ответы (2)


Я думаю, что вы могли бы создать специальную директиву для этого. Эта директива будет прикреплена к тому же элементу HTML, который содержит элемент routerLink. Таким образом, у вас будет доступ как к собственному элементу, так и к директиве 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

Изменить

Как предложено в проблеме от Брэндон, мы могли бы перегенерировать инструкцию компонента из значения, указанного в атрибуте 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);
  }

  (...)
}
person Thierry Templier    schedule 16.03.2016
comment
Мне это нравится, и видите, я был очень близок к вашему решению, пожалуйста, просто скажите мне, как я могу сделать этот элемент без рендеринга (я не хочу просто скрывать в стиле css - моя ошибка с почтовым вопросом, я имею в виду скрытый = нет -рендерер) - person Power Web Design; 16.03.2016
comment
Да, вы определенно правы! Использование @HostBinding для этого - лучшее решение ;-) Я соответственно обновил свой ответ и plunkr... - person Thierry Templier; 16.03.2016
comment
Все еще есть некоторые проблемы с этим, bcs находит 2 ошибки: - [первая] ссылка не скрывается - [вторая] ошибка TS2341: свойство '_navigationInstruction' является закрытым и доступно только в классе 'RouterLink' (не знаю, почему это работает в плунжер) - person Power Web Design; 17.03.2016
comment
На самом деле, это потому, что plunkr использует транспиляцию, а не компиляцию, поэтому вы можете вызывать приватные методы, но это не очень хорошо... Когда вы пытаетесь скомпилировать свое приложение, это нормально, чтобы иметь ошибки. На самом деле, я думаю, что лучшим подходом было бы предоставить патч для самого angular2. Таким образом, вы могли бы получить доступ к routeData из RouterLink... - person Thierry Templier; 17.03.2016
comment
Что-то вроде: this.routerLink.getRouteData(); - person Thierry Templier; 17.03.2016
comment
Я обновил свой первый пост с вопросом, у bcs есть проблема с многоуровневым меню и доступом к маршрутизатору. Ссылка на мой раздел расширенных данных: Вторая версия - person Power Web Design; 18.03.2016
comment
есть идеи, как это реализовать в последней угловой версии? - person Zasuk; 07.10.2016
comment
@ThierryTemplier, не могли бы вы указать мне пример решения для ABAC (управление доступом на основе атрибутов) в скрипте Angular 2 Type. Я хочу установить пользовательские меню с разрешениями на основе атрибутов. некоторые меню будут скрыты. а некоторые показаны с разделами с ограниченным доступом - person Kaleem Ullah; 25.04.2017

когда маршрут становится активным в angular2, он по умолчанию добавляет к ссылке класс .router-link-active.

Так что я 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:'...'
)}
person micronyks    schedule 16.03.2016
comment
Это то, что тебе надо? - person micronyks; 16.03.2016
comment
Спасибо за ваш ответ, но я хочу скрыть-удалить ссылку, если у посетителя нет доступа ACL к источнику (ссылка). Не скрывать активную ссылку, как вы говорите. - person Power Web Design; 16.03.2016