如果插入的内容为空,如何隐藏元素?

11

我创建了一个非常简单的指令,用于显示键/值对。 如果插入的内容为空(长度为零或只有空白字符),我希望能自动隐藏该元素。

我无法弄清如何从指令中访问被插入的内容。

app.directive('pair', function($compile) {
  return {
    replace: true,
    restrict: 'E',
    scope: {
      label: '@'
    },
    transclude: true,
    template: "<div><span>{{label}}</span><span ng-transclude></span></div>"
  }
});
例如,我希望显示以下元素。
<pair label="My Label">Hi there</pair>

但是接下来的两个元素应该被隐藏,因为它们不包含任何文本内容。

<pair label="My Label"></pair>
<pair label="My Label"><i></i></pair>

我刚接触Angular,也许有现成的好方法来处理这种情况。感谢任何帮助。

6个回答

9
这里提供一种方法,使用模板上的ng-show和在compile transcludeFn中检查传输的HTML是否具有文本长度。
如果没有文本长度,则ng-show将被设置为隐藏。
app.directive('pair', function($timeout) {
  return {
    replace: true,
    restrict: 'E',
    scope: {
      label: '@'
    },
    transclude: true,
    template: "<div ng-show='1'><span>{{label}} </span><span ng-transclude></span></div>",
    compile: function(elem, attrs, transcludeFn) {
            transcludeFn(elem, function(clone) { 
              /* clone is element containing html that will be transcludded*/
               var show=clone.text().length?'1':'0'
                attrs.ngShow=show;
            });
        }
  }
});

Plunker demo


1
+1 对于任何展示奇怪的 transcludeFn 用例的答案。请提供翻译文本。 - Mark Rajcok
1
在 transcludeFn 中,clone.text().trim().length 会更加准确。 - alalonde

6

也许有点晚了,但您也可以考虑使用CSS伪类:empty。这样就可以实现(IE9+)

.trancluded-item:empty {
  display: none;
}

该元素仍将在DOM中注册,但是它将是空的且不可见。

1
这非常优雅,也适用于非AngularJS应用程序。 - Austin Lovell

1
如果您不想每次都使用ng-show,您可以创建一个指令来自动执行它:
.directive('hideEmpty', ['$timeout', function($timeout) {

    return {
        restrict: 'A',

        link: {
            post: function (scope, elem, attrs) {
                $timeout(function() {
                    if (!elem.html().trim().length) {
                        elem.hide();
                    }
                });
            }
        }
    };

}]);

然后您可以将其应用于任何元素。在您的情况下,它将是:
<span hide-empty>{{label}}</span>

1
之前提供的答案有帮助,但并没有完美地解决我的情况,所以我通过创建一个单独的指令提出了不同的解决方案。
创建一个基于属性的指令(即restrict: 'A'),简单地检查所有元素子节点上是否有任何文本。
function hideEmpty() {
    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            let hasText = false;

            // Only checks 1 level deep; can be optimized
            element.children().forEach((child) => {
                hasText = hasText || !!child.text().trim().length;
            });

            if (!hasText) {
                element.attr('style', 'display: none;');
            }
        }
    };
 }

angular
    .module('directives.hideEmpty', [])
    .directive('hideEmpty', hideEmpty);

如果您只想检查主要元素:
link: function (scope, element, attr) {
    if (!element.text().trim().length) {
        element.attr('style', 'display: none;');
    }
}

为了解决我的问题,我只需要检查是否有任何子节点:
link: function (scope, element, attr) {
    if (!element.children().length) {
        element.attr('style', 'display: none;');
    }
}

YMMV


0
我是这样做的,使用了controllerAs。
/* 在指令内部 */
         controllerAs: "my",
controller: function ($scope, $element, $attrs, $transclude) {
//whatever controller does
},
         compile: function(elem, attrs, transcludeFn) {
                    var self = this;
                    transcludeFn(elem, function(clone) {
                        /* clone is element containing html that will be transcluded*/
                        var showTransclude = clone.text().trim().length ? true : false;
                        /* I set a property on my controller's prototype indicating whether or not to show the div that is ng-transclude in my template */
                        self.controller.prototype.showTransclude = showTransclude;
                    });
                }

/* 在模板内部 */

<div ng-if="my.showTransclude" ng-transclude class="tilegroup-header-trans"></div>

0

我对transclude不是很熟悉,所以不确定它是否有帮助。

但是,在指令代码内部检查空内容的一种方法是使用iElement.text()或iElement.context对象,然后隐藏它。


谢谢。实际上,我尝试在“link”函数中做这个,但是那时候内容尚未被传递进来。 - jessegavin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接