从内部范围调用element.replaceWith。$ on throws TypeError

时间:2014-01-16 11:59:29

标签: angularjs angularjs-directive

我们有以下指令:

.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);
            });
        }
    }
})

这个想法是基于特征切换(或特征标志)的值,指令将输出带有标记的注释,或仅输出注释。

初始的element.replaceWith按预期工作,但是来自范围内的调用。$ on会生成“TypeError:无法调用方法'replaceChild'的null”。我们在每次通话之前都检查了元素,但没有发现明显的差异。

任何人都可以解释为什么会抛出错误,或者建议一个可以让我们做同样事情的潜在解决方法吗?

我们有一个工作指令,用于设置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中删除元素,而不是将display设置为none。

1 个答案:

答案 0 :(得分:1)

您仍然可以在自定义“directiveToggle”中使用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;
            });
        }
    }
});

以上是从“directiveToggle”中取出标记,然后将其包装在模板内部,其中“ng-transclude”指令标记插入点。模板中还包含一个“ng-if”指令,它在“directiveTemplate”的当前作用域上观察“isEnabled”成员。

这种方法的一个警告是,如果你有这个指令的多个实例,你需要指令来创建它自己的范围/隔离范围,否则“isEnabled”成员将在指令之间共享。