2013-04-02 2 views
9

Я создал очень простую директиву, которая отображает пару ключ/значение. Я хотел бы, чтобы иметь возможность автоматически скрывать элемент, если транслируемый контент пуст (либо нулевая длина, либо просто пробел).Как скрыть элемент, если содержимое вложенных файлов пуст?

Я не могу понять, как получить доступ к контенту, который переводится из директивы.

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, поэтому может быть отличная ручка такого рода из коробки. Любая помощь приветствуется.

ответ

8

Вот такой подход, используя 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 для любого ответа, который показывает пример использования для esoteric transcludeFn :). –

+1

в transcludeFn, 'clone.text(). Trim(). Length' будет немного точнее – alalonde

+0

+1 спасибо, это просто спасло меня много времени. – cgTag

0

Я не очень хорошо знаком с transclude, поэтому не уверен, помогает ли это или нет.

, но один способ проверить пустое содержимое внутри директивного кода - использовать объект iElement.text() или iElement.context, а затем скрыть его.

+0

Спасибо. Я на самом деле пытался сделать это в функции «link», но содержимое еще не было переведено на этот момент. – jessegavin

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> 
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

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> 
2

Может быть, немного поздно, но вы можете также рассмотреть возможность использования CSS Псевдо-класс: пусто. Таким образом, это будет работать (IE9 +)

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

Элемент по-прежнему будет зарегистрирован в йот, но будет пустым и невидимым.

Смежные вопросы