从内部 scope.$on 调用 element.replaceWith 会抛出 TypeError



我们有以下指令:

.directive("directiveToggleElement", function(FlagsService) {
    return {
        restrict: "E",
        scope: {},
        link: function(scope, element, attrs)
        {
            scope.showMe = FlagsService.isOn(attrs.toggleKey);
            scope.featureText = attrs.featureText;
            var htmlTag = '<div class="panel ng-scope" ng-class="{selected: selected}" ng-click="selected = !selected;"></div>';
            var htmlComment = '<!-- TogglePlaceholder: ' + attrs.toggleKey +'-->';
            element.replaceWith(scope.showMe ? htmlComment + htmlTag : htmlComment);
            // Listen for change broadcast from flagsservice to toggle local store
            scope.$on('LocalStorage.ToggleChangeEvent.' + attrs.toggleKey, function(event, parameters) {
                console.log('stuff changed - ' + parameters.key  + ' ' + parameters.newValue);
                scope.showMe  = parameters.newValue;
                element.replaceWith(scope.showMe  ? htmlComment + htmlTag : htmlComment);
            });
        }
    }
})

这个想法是,根据功能切换(或功能标志)的值,指令将输出带有标签的注释,或者仅输出注释。

初始元素 .replaceWith 按预期工作,但从 scope.$on 内部的调用会生成"类型错误:无法调用 null 的方法'replaceChild'"。我们在每次调用之前都检查了元素,无法发现明显的差异。

谁能解释为什么错误会被抛到这里,或者建议一种潜在的解决方法,使我们能够做同样的事情?

我们有一个工作指令来设置 ng-show 的值:

.directive("directiveToggle", function(FlagsService) {
    return {
        restrict: "A",
        transclude: true,
        scope: {},
        link: function(scope, element, attrs)
        {
            scope.showMe = FlagsService.isOn(attrs.toggleKey);
            // Listen for change broadcast from flagsservice to toggle local store
            scope.$on('LocalStorage.ToggleChangeEvent.' + attrs.toggleKey, function(event, parameters) {
                console.log('stuff changed - ' + parameters.key  + ' ' + parameters.newValue);
                scope.showMe = parameters.newValue;
            });
        },
        template: '<div class="panel ng-scope" ng-show="showMe" ng-class="{selected: selected}" ng-click="selected = !selected;"><span ng-transclude></span></div>',
        replace: true
    }
})

但是我们更愿意从 DOM 中删除元素,而不是将显示设置为 none。

您仍然可以在自定义"指令切换"中使用 ng-if 指令,而无需控制器。要实现此目的,您需要使用 transclude 选项:

.directive("directiveToggle", function (FlagsService) {
    return {
        template: '<div ng-transclude ng-if="isEnabled"></div>',
        transclude: true,
        restrict: 'A',
        scope: true,
        link: function ($scope, $element, $attrs) {
            var feature = $attrs.featureToggle;
            $scope.isEnabled = FlagsService.isOn(feature);
            $scope.$on('LocalStorage.ToggleChangeEvent.' + feature, function (event, parameters) {
                $scope.isEnabled = parameters.newValue;
            });
        }
    }
});

上面是从"指令切换"内部获取标记,然后将其包装在模板中,其中"ng-transclude"指令标记插入点。模板中还包括一个"ng-if"指令,该指令正在监视"directiveTemplate"的当前作用域上的"isEnabled"成员。

此方法的一个警告是,如果您有多个此指令实例,则需要指令来创建其自己的作用域/隔离作用域,否则"isEnabled"成员将在指令之间共享。

最新更新