Detect if a transclude content has been given for a angularjs directive

13,473

Solution 1

After release of Angular v1.5 with multi-slot transclusion it's even simpler. For example you have used component instead of directive and don't have access to link or compile functions. Yet you have access to $transclude service. So you can check presence of content with 'official' method:

app.component('myTransclude', {
  transclude: {
    'slot': '?transcludeSlot'
  },
  controller: function ($transclude) {
    this.transcludePresent = function() {
      return $transclude.isSlotFilled('slot');
    };
  }
})

with template like this:

<div class="progress" ng-class="{'with-label': withLabel}">
    <div class="label"><span ng-transclude="slot"></span>
    <div class="other">...</div>
</div>

Solution 2

Based on @Ilan's solution, you can use this simple $transclude function to know if there is transcluded content or not.

$transclude(function(clone){
    if(clone.length){
        scope.hasTranscluded = true;
    }
});

Plnkr demonstrating this approach with ng-if to set default content if nothing to transclude: http://plnkr.co/hHr0aoSktqZYKoiFMzE6

Solution 3

Here is a plunker: http://plnkr.co/edit/ednJwiceWD5vS0orewKW?p=preview

You can find the transcluded element inside the linking function and check it's contents:

Directive:

app.directive('progressbar', function(){
  return {
    scope: {},
    transclude: true,
    templateUrl: "progressbar.html",
    link: function(scope,elm){
      var transcluded = elm.find('span').contents();
      scope.withLabel = transcluded.length > 0; // true or false
    }
  }
})

Template:

<div class="progress" ng-class="{'with-label': withLabel}">
    <div class="label"><span ng-transclude></span>
    <div class="other">...</div>
</div>

You can also create your custom transclusion directive like so:

app.directive('myTransclude', function(){

  return {
    link: function(scope, elm, attrs, ctrl, $transclude){
      $transclude(function(clone){

        // Do something with this:
        // if(clone.length > 0) ...

        elm.empty();
        elm.append(clone);
      })
    }
  }
})
Share:
13,473

Related videos on Youtube

Sebastian
Author by

Sebastian

Software Developer with focus on mobile &amp; web applications, highly addicted to test &amp; behaviour driven development, passionate about intelligent software systems. Interested in new technologies, web applications, SaaS and PaaS solutions. Strong background in Ruby on Rails, HTML5, Phonegap/Cordova, Javascript, Heroku. Some experience on Java (plain and for Android), ObjectiveC, C#.

Updated on June 06, 2022

Comments

  • Sebastian
    Sebastian about 2 years

    I have a directive (a progressbar) which should have two possible states, one without any description and one with a label on the left side. It would be cool to simple use the transcluded content for this label.

    Does anyone know how I can add a class to my directive depending whether a transclude content has been given or not?

    So I want to add:

    <div class="progress" ng-class="{withLabel: *CODE GOES HERE*}">
        <div class="label"><span ng-transclude></span>
        <div class="other">...</div>
    </div>
    

    Thanks a lot!

  • Sebastian
    Sebastian over 10 years
    Thanks thats awesome!
  • John Ding
    John Ding about 10 years
    llan, you have some code commented out, in what case can this be true? clone.length > 0, I tested, it is always 1
  • plong0
    plong0 almost 9 years
    you would have !clone.length if there is nothing to transclude (ie empty <progressbar></progressbar>)
  • pilau
    pilau almost 8 years
    Exactly what I was looking for!
  • Robba
    Robba over 7 years
    This works well when using the multi-slot feature. But what if I just use the transclude: true setting on the component and want to know if any content is provided?
  • Snook
    Snook almost 7 years
    Shouldn't ng-class be: ng-class="{'with-label': transcludePresent}" ?
  • Paul Carlton
    Paul Carlton over 5 years
    This looks like the most straight forward and quickest way in a component. Within the component controller, inject $transclude and then use this function when it runs before $onInit() is called.