我一直在努力解决以下问题。
我有一个自定义指令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
),当两个指令具有相同的优先级时,根据文档按字母顺序执行它们。 This post非常有助于理解这一点。
所以我在这里有一些选择:
让我的authorize指令评估ng-hide
或ng-show
中的条件以便计算(即:如果ng-hide表示该元素应该显示但是用户没有特定组,那么元素应该隐藏)。 我找不到在我的指令链接功能中访问myVm.isDeleted
的方法。如果有人知道我对这种方法感到满意。
让我的authorize
指令在任何其他指令之前执行,并依赖于角度稍后根据ng-show
或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);
}
答案 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>
简单易读。