0

对于以下情况,我一直在努力使用我的方法。我有一个自定义指令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-showorng-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指令在任何其他指令之前执行,并依赖 angular 稍后根据ng-showor确定可见性ng-hide(即:如果我的authorize指令确定元素应该隐藏,因为用户不属于给定的组,那么它应该转换 DOM元素并制作它ng-show="false",以便稍后隐藏元素。这种方法似乎不起作用,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);
}
4

1 回答 1

2

我认为你的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>

读起来又好又简单。

于 2016-11-04T01:42:11.853 回答