同一元素中的多个指令对可见性进行操作
Multiple directives in same element operating on visibility
我一直在努力解决以下情况。
我有一个自定义指令 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
中使用 link 函数的原始指令(因为我在 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 returns 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 表示应该显示该元素但用户没有特定的组,则应隐藏该元素)。 我无法在指令 link 的函数 中找到访问 myVm.isDeleted
的方法。如果有人知道我会对这种方法感到满意。
让我的 authorize
指令在任何其他指令之前执行,并依赖 angular 稍后根据 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);
}
我认为,鉴于您的 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>
简洁易读。
我一直在努力解决以下情况。
我有一个自定义指令 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
中使用 link 函数的原始指令(因为我在 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 returns 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 表示应该显示该元素但用户没有特定的组,则应隐藏该元素)。 我无法在指令 link 的函数 中找到访问myVm.isDeleted
的方法。如果有人知道我会对这种方法感到满意。让我的
authorize
指令在任何其他指令之前执行,并依赖 angular 稍后根据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);
}
我认为,鉴于您的 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>
简洁易读。