【问题标题】:How to hide element if transcluded contents are empty?如果嵌入的内容为空,如何隐藏元素?
【发布时间】:2013-03-24 00:10:45
【问题描述】:

我创建了一个显示键/值对的非常简单的指令。如果嵌入的内容为空(零长度或只是空格),我希望能够自动隐藏元素。

我不知道如何访问从指令中嵌入的内容。

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 的新手,所以可能有一种开箱即用的好方法来处理这类事情。任何帮助表示赞赏。

【问题讨论】:

    标签: angularjs angularjs-directive transclusion


    【解决方案1】:

    可能有点晚了,但您也可以考虑使用 CSS 伪类 :empty。 所以,这会工作(IE9+)

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

    该元素仍将在 dom 中注册,但将为空且不可见。

    【讨论】:

    • 这非常优雅,也适用于非 angularjs 应用程序。
    【解决方案2】:

    如果你不想每次都使用 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>
    

    【讨论】:

      【解决方案3】:

      之前提供的答案很有帮助,但并没有完美地解决我的情况,所以我通过创建单独的指令想出了一个不同的解决方案。

      创建一个基于属性的指令(即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

      【讨论】:

        【解决方案4】:

        我是这样做的,使用 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>
        

        【讨论】:

          【解决方案5】:

          这是一种在模板上使用 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 表示任何显示深奥 transcludeFn 用例的答案 :)。
          • 在 transcludeFn 中,clone.text().trim().length 会更准确一些
          【解决方案6】:

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

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

          【讨论】:

          • 谢谢。我实际上尝试在 link 函数中这样做,但到那时内容还没有被嵌入。
          猜你喜欢
          • 1970-01-01
          • 2013-04-27
          • 2014-02-27
          • 2012-01-08
          • 1970-01-01
          • 2017-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多