Несколько директив в одном элементе, работающем на видимости
Я боролся с моим подходом к следующему сценарию. У меня есть специальная директива 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
) в директивах, когда две директивы имеют одинаковый приоритет, они выполняются в алфавитном порядке в соответствии с документацией. Этот пост был очень полезен, чтобы понять это.
Итак, у меня есть несколько вариантов здесь:
Пусть моя директива санкционирует оценку условного
ng-hide
или жеng-show
для вычисления (то есть: если ng-hide говорит, что элемент должен быть показан, но у пользователя нет определенной группы, то элемент должен быть скрыт). Я не мог найти способ доступаmyVm.isDeleted
в функции моей директивы ссылки. Если кто-нибудь знает, как я был бы счастлив с таким подходом.Есть мой
authorize
Директива выполняется ДО любой другой директивы и зависит от угла, чтобы в дальнейшем определить видимость согласно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);
}
1 ответ
Я бы сказал, что видя, как ваш 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>
Приятно и просто читать.