Несколько директив в одном элементе, работающем на видимости

Я боролся с моим подходом к следующему сценарию. У меня есть специальная директива authorize где я передаю название группы. Если текущий пользователь имеет эту группу в своем профиле, то элемент будет виден, если не элемент будет скрыт. Пример:

<button class="btn btn-default" role="button"
        ng-click="myVm.edit()"
        authorize="{{myVm.groupName}}"><!--groupName = "accountants"-->
    <span class="fa fa-edit" aria-hidden="true"></span> Edit
</button>

и моя оригинальная директива в машинописи authorize.ts используя функцию связи (потому что я работаю на DOM)

namespace app.blocks.directives {
    "use strict";

    class AuthorizeDirective implements ng.IDirective {

        public restrict: string = "A";

        public replace: boolean = true;

        constructor(private $compile: ng.ICompileService, private authService: services.IAuthService) {
        }

        public static factory(): ng.IDirectiveFactory {
            const directive = ($compile: ng.ICompileService, authService: services.IAuthService) =>
                new AuthorizeDirective($compile, authService);
            directive.$inject = [
                "$compile",
                "app.services.AuthService"
            ];
            return directive;
        }

        public link(scope: ng.IScope, instanceElement: ng.IAugmentedJQuery, instanceAttributes: ng.IAttributes): void {
            let groupName: string = (<any>instanceAttributes).authorize;
            let element = angular.element(instanceElement);
            let hasGroup: boolean = this.authService.hasGroup(groupName);
            element.attr("ng-show", String(hasGroup));
            //remove the attribute, otherwise it creates an infinite loop.
            element.removeAttr("authorize");
            this.$compile(element)(scope);
            }
        }
    }

    angular
        .module("app.blocks.directives")
        .directive("authorize", AuthorizeDirective.factory());
}

Это работает нормально, кнопка скрыта, если authService возвращает false, потому что пользователь не принадлежит к этой группе (то есть: "accountants").

Проблема появляется, когда мой элемент DOM имеет ng-show или же ng-hide директивы также. Пример:

<button class="btn btn-default" role="button"
        ng-hide="myVm.isDeleted"
        ng-click="myVm.edit()"
        authorize="{{myVm.groupName}}">
    <!--groupName = "accountants"-->
    <span class="fa fa-edit" aria-hidden="true"></span> Edit
</button>

когда myVm.isDeleted = true кажется, что переопределяет результат моей директивы, и отображается элемент DOM (если это не так, потому что пользователь не принадлежит к указанной группе в соответствии с моим authorize Директива).

Я понимаю, что есть какой-то приоритет (по умолчанию 0) в директивах, когда две директивы имеют одинаковый приоритет, они выполняются в алфавитном порядке в соответствии с документацией. Этот пост был очень полезен, чтобы понять это.

Итак, у меня есть несколько вариантов здесь:

  1. Пусть моя директива санкционирует оценку условного ng-hide или же ng-show для вычисления (то есть: если ng-hide говорит, что элемент должен быть показан, но у пользователя нет определенной группы, то элемент должен быть скрыт). Я не мог найти способ доступа myVm.isDeleted в функции моей директивы ссылки. Если кто-нибудь знает, как я был бы счастлив с таким подходом.

  2. Есть мой authorize Директива выполняется ДО любой другой директивы и зависит от угла, чтобы в дальнейшем определить видимость согласно ng-show или же ng-hide (т.е. если мой authorize Директива определяет, что элемент должен быть скрыт, потому что пользователь не принадлежит данной группе, тогда он должен преобразовать элемент DOM и сделать его ng-show="false" например, так что angular скрывает элемент позже. Этот подход, кажется, не работает, DOM кажется правильным, я вижу, что кнопка имеет ng-show="false", но по какой-то причине я все еще вижу кнопку на экране, так что как будто Angular не знал, что она имеет чтобы скрыть этот элемент. Самое смешное, что если я перехожу на другую вкладку и возвращаюсь на ту же вкладку (представление перезагружается и директива выполняется заново), то это работает нормально. В чем дело?,

Я выбрал вариант 2, и это код, который, кажется, работает должным образом, манипулируя DOM, но Angular впоследствии не применяет директиву ng-show, потому что результат не такой, как ожидалось.

public priority: number = 999; //High priority so it is executed BEFORE ng-show directive

public link(scope: ng.IScope, instanceElement: ng.IAugmentedJQuery, instanceAttributes: ng.IAttributes): void {
    let groupName: string = (<any>instanceAttributes).authorize;
    let element = angular.element(instanceElement);
    let ngShow: string = (<any>instanceAttributes).ngShow;
    let ngHide: string = (<any>instanceAttributes).ngHide;
    let hasGroup: boolean = this.authService.hasGroup(groupName);
    let ngHideValue = ngHide ? "!" + ngHide : "";
    let ngShowValue = ngShow ? ngShow : "";
    //if hasGroup, use whatever ng-show or ng-hide value the element had (ng-show = !ng-hide).
    //if !hasGroup, it does not matter what value the element had, it will be hidden.
    if (hasGroup) {
        element.attr("ng-show", (ngShowValue + ngHideValue) || "true");
    } else {
        element.attr("ng-show", "false");
    }
    element.removeAttr("ng-hide");
    //remove the attribute, otherwise it creates an infinite loop.
    element.removeAttr("authorize");
    this.$compile(element)(scope);
}

1 ответ

Решение

Я бы сказал, что видя, как ваш authorize Директива в основном просто контролирует, отображает ли размещаемый элемент элемент или нет, вы должны просто переместить его логику в сервис, который вы вставляете в свой контроллер, и позволить ng-hide контролировать, отображает ли элемент, как он предназначен.

Разработчикам, которые придут позже, будет легче понять - никто не хочет углубляться в отдельные директивы, чтобы найти различные разбросанные фрагменты кода, которые вызывают сервер, и ваша кнопка будет выглядеть так:

<button class="btn btn-default" role="button"
    ng-hide="myVm.isDeleted || !myVm.isAuthorized(myVm.groupName)"
    ng-click="myVm.edit()">
    <span class="fa fa-edit" aria-hidden="true"></span> Edit
</button>

Приятно и просто читать.

Другие вопросы по тегам