如何触发已删除元素范围的$ destroy事件?

时间:2015-07-07 09:42:55

标签: angularjs angularjs-directive

考虑以下指令:

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" (不,我没有删除节点,我添加了一个数据属性,并希望将其置于链接函数中:$element.data('remove', true)然后想要$ destroy和remove())。编辑:这似乎是ngInclude指令的转换行为。

如果我从link-function中删除$ scope。$ destroy()并删除该节点,则ngInclude-directive仍在运行...

我想要什么?我只是想在编译时从DOM中删除元素,因为当前用户没有查看此元素/指令/视图的权限,我也想避免进一步处理指令(在我的情况下,ng-include不应该是不必要的)请求模板(因为我们的服务器无论如何都会响应401)等等。

更新:我想我需要一种在编译函数内部设置terminal选项的方法来停止处理即将发生的指令。我的问题是ngInclude正在运行,即使之前删除了该元素。

1 个答案:

答案 0 :(得分:1)

找到解决方案!我还必须使用transclusion(在我检查ngIf的impl之后很明显)并且它唯一可能在(pre / post)链接函数内部,所以这里是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'];

我也把实现外包给控制器,所以我可以重用逻辑,但我不想提供一个完整的例子来澄清:)