How to replace the element with ng-transclude

27,556

Solution 1

I think the best solution would probably be to create your own transclude-replace directive that would handle this. But for a quick and dirty solution to your example you could essentially manually place the result of the transclusion where you want:

my-transcluded-directive.html:

<div>
    <span>I WILL BE REPLACED</span>
    <div>I will not be touched.</div>
</div>

Directive:

return {
    restrict:'A',
    templateUrl:'templates/my-transcluded-directive.html',
    transclude:true,
    link:function(scope,element,attrs,ctrl, transclude)
    {
         element.find('span').replaceWith(transclude());
    }
};

Solution 2

It's easy to create a ng-transclude-replace directive, here is a copycat of the original ng-transclude.

directive('ngTranscludeReplace', ['$log', function ($log) {
              return {
                  terminal: true,
                  restrict: 'EA',

                  link: function ($scope, $element, $attr, ctrl, transclude) {
                      if (!transclude) {
                          $log.error('orphan',
                                     'Illegal use of ngTranscludeReplace directive in the template! ' +
                                     'No parent directive that requires a transclusion found. ');
                          return;
                      }
                      transclude(function (clone) {
                          if (clone.length) {
                              $element.replaceWith(clone);
                          }
                          else {
                              $element.remove();
                          }
                      });
                  }
              };
          }]);

PS:you can also check this link to see the difference between the ng-transclude

Solution 3

this works in Angular 1.4.9 (and prob earlier too)

return {
      restrict: 'E',
      replace: true,
      template: '<span data-ng-transclude></span>',
      transclude: true,
      link: function (scope, el, attrs) .........
}

Solution 4

If you don't have to support IE and Edge you can use display:contents in your css. That will destroy the wrapper on the level of css.

You can read more about this new display propertie here: https://css-tricks.com/get-ready-for-display-contents/

Current browser support (hope to see Edge support in the future): https://caniuse.com/#feat=css-display-contents

Share:
27,556
Francisc
Author by

Francisc

Updated on June 06, 2020

Comments

  • Francisc
    Francisc about 4 years

    Is it possible to replace the element with ng-transclude on it rather than the entire template element?

    HTML:

    <div my-transcluded-directive>
        <div>{{someData}}</div>
    </div>
    

    Directive:

    return {
        restrict:'A',
        templateUrl:'templates/my-transcluded-directive.html',
        transclude:true,
        link:function(scope,element,attrs)
        {
    
        }
    };
    

    my-transcluded-directive.html:

    <div>
        <div ng-transclude></div>
        <div>I will not be touched.</div>
    </div>
    

    What I am looking for is a way to have <div>{{someData}}</div> replace <div ng-transclude></div>. What currently happens is the transcluded HTML is placed inside the ng-transclude div element.

    Is that possible?

  • Belladonna
    Belladonna over 9 years
    For me element finds div[my-transcluded-directive], not the template.
  • swehren
    swehren over 9 years
    @LittleBigBot if you want to post a fiddle I'll take a look
  • Alex White
    Alex White over 9 years
    Thank you! I've been searching for a viable solution that works with a directive that uses transclusion but is also a part of an ng-repeat. The accepted solution works but not with ng-repeat. I am thinking it has to do with terminal: true. The best part is that the user of this code doesn't have to know it for it to work :)
  • fracz
    fracz almost 9 years
    Note that you need to compile the contents if there are some directives: .replaceWith($compile(transclude())(scope))
  • maow
    maow almost 9 years
    Thanks. This replace trick won't work, if some child directive has dependency on the parent.
  • Jon Onstott
    Jon Onstott about 8 years
    Another snippet of code that can help in some situations is element.find('span').replaceWith(transclude().clone());
  • Roaders
    Roaders over 7 years
    Brilliant. Just what I wanted thank you very much. IMHO this should be the default behaviour for transclude rather than leaving empty, useless extra nesting Dom elements everywhere!
  • Simone Campagna
    Simone Campagna about 5 years
    @Jonny Henry Briggs your fiddle doesn't appear to mantain "<div>I will not be touched.</div>" element. Your compiled doesn't report that element. So something is wrong :(