angularjsangularjs-directiveangularjs-ng-transclude

Detecting if optional transcluded elements are used in an AngularJS directive?


I have a directive set up in the style shown below; it allows for optional transcluded elements like the <dir-header> and <dir-footer> used in the example.

directive.js (partial)

module.directive('dir', function () {
    return {
        restrict: 'E',
        templateUrl: 'path/template.html',
        transclude: {
            'header': '?dirHeader',
            'footer': '?dirFooter'
        },
        link: function (scope, elem, attrs) {
            // do something
        }
    };
});

template.html

<div ng-transclude="header">
  <!-- Transcluded header will appear here -->
</div>

<div class="static-content">
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>

<div ng-transclude="footer">
    <!-- Transcluded footer will appear here -->
</div>

Usage

<dir>
    <dir-header>My Header</dir-header>
    <dir-footer>My Footer</dir-footer>
</dir>

Based on what I have here is there a way to detect if <dir-header> is being used? Can I access the content passed into it—in this case the string "My header"—from the link function?


Some background on what I've done so far:

I've seen a few discussions on this topic using the transclude: true style rather than transclude: {}. Based on suggestions found from that research I tried the following:

link: function (scope, elem, attrs, $transclude) {
    $transclude(function (clone) {
        console.log(clone);
    });
}

I couldn't quite discern how clone works but it seems to be a NodeList representing what has been transcluded. Unfortunately the only piece of useful information I get from this is a length; clone.length for my usage example above would be 3 (one for dir, header, and footer). If I remove footer the length would be 2, and so on. There doesn't seem to be any data to differentiate the elements in the NodeList, though, so I can't tell which transcluded elements are being used, just how many.

Ultimately I would like to set some style conditions based on whether a particular transcluded element is being used or not.


Solution

  • isSlotFilled function on the transclude function will give you the desired result.

    angular.module('App', [])
      .directive('dir', function () { 
        return {
            restrict: 'E',
            template: `
              <div ng-transclude="header"></div>
              <div class="static-content">
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
              </div>
    
              <div ng-transclude="footer">
            `,
            transclude: {
                'header': '?dirHeader',
                'footer': '?dirFooter'
            },
            link: function ($s, $el, $attrs, thisCtrl, $transclude) {
              console.log($transclude.isSlotFilled('header'))
              console.log($transclude.isSlotFilled('footer'))
            }
        };
      });
    

    working plnkr