在可见性

时间:2016-11-04 01:26:06

标签: angularjs typescript angularjs-directive ng-show angularjs-controlleras

我一直在努力解决以下问题。 我有一个自定义指令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-showng-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),当两个指令具有相同的优先级时,根据文档按字母顺序执行它们。 This post非常有助于理解这一点。

所以我在这里有一些选择:

  1. 让我的authorize指令评估ng-hideng-show中的条件以便计算(即:如果ng-hide表示该元素应该显示但是用户没有特定组,那么元素应该隐藏)。 我找不到在我的指令链接功能中访问myVm.isDeleted的方法。如果有人知道我对这种方法感到满意。

  2. 让我的authorize指令在任何其他指令之前执行,并依赖于角度稍后根据ng-showng-hide确定可见性(即:如果我的authorize }指令确定该元素应该被隐藏,因为用户不属于给定的组,然后它应该转换DOM元素并使其成为ng-show="false",以便角度稍后隐藏元素。这种方法可以似乎没有用, DOM似乎是正确的,我可以看到按钮有ng-show =“false”但由于某种原因我仍然看到屏幕上的按钮所以就好像Angular没有知道它必须隐藏那个元素。有趣的是,如果我移动到另一个选项卡,然后我回到相同的选项卡(重新加载视图并重新执行指令),那么它可以正常工作。什么是继续?

  3. 我使用选项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 个答案:

答案 0 :(得分: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>

简单易读。