2017-10-10 3 views
2

J'ai construit une directive 'accessLevel' dans l'angle 4 qui fonctionne comme * ngIf mais sur différents niveaux d'autorisations.Angular 4- Comment lier la propriété à la directive *

@Directive({ 
    selector: '[accessLevel]' 
}) 
export class AccessLevelDirective { 
    private levelToPredicateMapper: {[id: string] :() => Observable<boolean>} = {}; 
    private isAuthorized: boolean; 

    constructor(
    private templateRef: TemplateRef<any>, 
    private viewContainer: ViewContainerRef, 
    private readonly credentialsStorage: CredentialsStorageService, 
    private readonly authentication: AuthenticationService) { 

    this.createAccessLevelToPredicatesMapper(); 
    } 

    @Input() set accessLevel(level: string) { 
    if (level == null) { 
     return; 
    } 

    let hasAccessLevelFunc = this.levelToPredicateMapper[level]; 
    if (hasAccessLevelFunc == null) { 
     this.viewContainer.clear(); 
     return; 
    } 

    hasAccessLevelFunc().subscribe(hasAccessLevel => { 
     this.buildOrDestroyView(hasAccessLevel); 
    }) 
    } 

    @Input() set roles(roles: [string]) { 
    this.authentication.isAuthenticated() 
     .subscribe(isAuthenticated => { 

     let isValidRolesArray = roles != null && Array.isArray(roles) && roles.length > 0; 
     let isUserHasOneOfTheRoles = isAuthenticated && 
      isValidRolesArray && 
      this.credentialsStorage.get() && 
      some(this.credentialsStorage.get().roles , role => roles.indexOf(role) > -1); 
     this.buildOrDestroyView(isUserHasOneOfTheRoles); 
     }) 
    } 

    private buildOrDestroyView(isAuthorized: boolean) { 
    let isStateChanged = isAuthorized !== this.isAuthorized; 
    if (!isStateChanged) return; 
    this.isAuthorized = isAuthorized; 

    if (isAuthorized) { 
     this.viewContainer.createEmbeddedView(this.templateRef); 
    } else { 
     this.viewContainer.clear(); 
    } 
    } 

    private createAccessLevelToPredicatesMapper() { 
    this.levelToPredicateMapper['all'] =() => Observable.of(true); 
    this.levelToPredicateMapper['guest'] =() => this.authentication.isAuthenticated().map(isAuth => !isAuth); 
    this.levelToPredicateMapper['authenticated'] =() => this.authentication.isAuthenticated() 
    } 
} 

Mon problème est lorsque je l'utilise à l'intérieur du code HTML. afin de lier à la propriété de rôle, j'ai besoin d'envelopper l'élément avec ng-template.

<!--Without [roles]--> 
<a class="nav-item nav-link text-uppercase" *accessLevel="'authenticated'"> 
    ...   
</a> 
<!--with [roles]--> 
<ng-template accessLevel [roles]="['admin']"> 
    ... 
</ng-template> 

Est-il possible que je peux lier les rôles sans qu'il soit nécessaire d'envelopper l'élément avec ng-modèle?

Répondre

1

Lorsque le nom d'entrée est le même que le sélecteur

<input *accessLevel="['admin']" ... 

devraient travailler

sinon l'entrée doit être

@Input() set accessLevelRoles(roles: [string]) { 

puis

<input *accessLevel="roles:['admin']" ... 

devrait fonctionner .

+1

Semble '* accessLevel =" rôles: ['admin'] "' ne se trompe pas. '' accessLevel = "quelque chose; roles: ['admin']" ' – yurzui

+0

Bon, je suis déjà tombé sur quelque chose comme ça il y a un moment. –

+0

'* accessLevel =" 0, rôles: ['admin'] "' ou '* accessLevel =" 'authentifié', rôles: ['admin'] "' – yurzui