【发布时间】:2017-03-17 18:30:30
【问题描述】:
我一直在努力解决以下情况。
我有一个自定义指令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>
以及我在 typescript 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 对理解这一点很有帮助。
所以我在这里有一些选择:
让我的授权指令评估
ng-hide或ng-show中的条件以便计算(即:如果 ng-hide 说应该显示元素但用户没有特定组,那么该元素应该被隐藏)。 我在指令链接的函数中找不到访问myVm.isDeleted的方法。如果有人知道我会对这种方法感到满意。在任何其他指令之前执行我的
authorize指令,并依赖 angular 稍后根据ng-show或ng-hide确定可见性(即:如果我的authorize指令确定元素应该是hidden 因为用户不属于给定的组,那么它应该转换 DOM 元素并使其成为ng-show="false"例如,以便 angular 稍后隐藏元素。这种方法似乎不起作用,DOM看起来是正确的,我可以看到按钮有 ng-show="false" 但由于某种原因我仍然在屏幕上看到按钮所以就好像 Angular 不知道它必须隐藏那个元素。有趣的是,如果我移动到另一个选项卡,然后我回到同一个选项卡(视图重新加载并重新执行指令),那么它工作正常。发生了什么?。。 p>
我选择了选项 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);
}
【问题讨论】:
-
一个明显的解决方法是将我的按钮包装在一个 div 中,并在 div 本身上应用
authorize指令,让按钮中的 ng-hide 不会在按钮本身上产生多个指令的冲突.但我想为我的问题找到一个解决方案,并理解为什么 angular 不会重新计算ng-show="false"
标签: angularjs typescript angularjs-directive ng-show angularjs-controlleras