Рассмотрим следующую директиву:
class HasPermissionDirective {
constructor(PermissionService) {
this.restrict = 'A';
this.priority = 1005;
this.PermissionService = PermissionService;
}
compile(element, attrs) {
let permission = _.trim(attrs.hasPermission),
hide = _.get(attrs, 'hideOnly'),
$element = angular.element(element);
if (permission && !this.PermissionService.hasPermission(permission)) {
if (!_.isUndefined(hide)) {
hide = _.trim(hide);
if (hide === 'visibility') {
$element.css('visibility', 'hidden');
} else {
$element.hide();
}
} else {
$element.remove();
}
}
}
link($scope, $element, attrs, ctrl) {
$scope.$destroy();
}
}
HasPermissionDirective.$inject = ['PermissionService'];
Проблема в том, что теперь $ scope. $ Destroy() выполняется всегда, для каждого элемента-области, к которой прикреплена директива (конечно).
Когда я теперь добавляю переменную-член "isRemoved" и устанавливаю ее в true, если элемент был удален и выполняет следующие функции связи:
if (this.isRemoved) {
$scope.$destroy();
}
Разумеется, $ scope. $ Destroy() запускается для каждого объекта-сферы, как только удаляется хотя бы один элемент, поэтому директива обрабатывается как одноточечная, а не как экземпляр.
Я не могу добавить какую-либо информацию к узлу элемента, поскольку он, кажется, удаляется после компиляции и является только узлом комментария "ngInclude: undefined" (нет, я не удаляю узел, добавляю атрибут data и хочу его получить внутри функции ссылки: $element.data('remove', true)
а затем хотите $ destroy и remove()). EDIT: Это похоже на transclude-поведение директивы ngInclude.
Если я удаляю $ scope. $ Destroy() из функции link и просто удаляю узел, директива ngInclude все еще работает...
Ват, я хочу? Я просто хочу удалить элемент из DOM во время компиляции, поскольку у текущего пользователя нет разрешения на просмотр этого элемента/директивы/представления, и я также хочу избежать дальнейшей обработки директив (в моем случае ng-include, который не должен быть лишним шаблоны запросов (так как наш сервер будет отвечать 401 в любом случае) и так далее).
UPDATE: Я думаю, мне нужен способ установить параметр terminal
внутри функции компиляции, чтобы остановить обработку предстоящих директив. Моя проблема в том, что ngInclude работает, хотя элемент был удален ранее.
Решение найдено! Я также должен использовать transclusion (было ясно после того, как я проверял impl ngIf) и его единственной возможной внутри (до/после) функции (-ов) ссылки, так что здесь impl. для тех, кто сталкивается с аналогичными проблемами:
class HasPermissionDirective {
constructor(PermissionService) {
this.restrict = 'A';
this.priority = 1011; // high prio so the element is removed before all other directives can be processed
this.transclude = 'element';
this.$$tlb = true; // BAD! But w/o, transclusion for different directives won't work :(
this.PermissionService = PermissionService;
}
preLink($scope, $element, attrs, ctrl, $transclude) {
let $newScope = $scope.$new(),
hide = _.get(attrs, 'hideOnly');
$transclude($newScope, ($clone) => {
if (!this.PermissionService.hasPermission(_.trim(attrs.hasPermission))) {
if (!_.isUndefined(hide)) {
hide = _.trim(hide);
if (hide === 'visibility') {
$clone.css('visibility', 'hidden');
} else {
$clone.hide();
}
} else {
$newScope.$destroy();
$newScope = null;
$clone.remove();
$clone = null;
}
} else {
// in case the user has the permission we have to attach the element to the DOM (cause of transclusion)
$element.after($clone);
}
});
}
}
HasPermissionDirective.$inject = ['PermissionService'];
Я также выполнил аутсорсинг реализации контроллеру, чтобы я мог повторно использовать логику, но я не предоставил полный пример для разъяснения :)