AngularJS Transclude

Break free from the DOM: move compiled elements to arbitrary locations

Transclusion allows a directive to move clone(s) of the contents of a directive to an arbitrary place in the DOM. Usually this is at the original location of the directive, wrapped in some extra elements, but it doesn't have to be. So why move the element? You might want components to still have access to the original scope, with any models and methods, but for page-layout or CSS reasons be elsewhere.

{{model.variable}}
<move>
  Contents bound to local scope {{model.variable}}
</move>

Example components that use this could be

  • Context menu
  • Dialog box
  • Sidebar
  • Alert box or notification area.

One thing to keep in mind is that you'll have to make sure you remove the element from the DOM when the original scope is destroyed. The high-level code would look like the following.

app.directive('move', function() {
  return {
    restrict: 'E',
    transclude: 'element',
    link: function(scope, element, attrs, controller, transclude) {
      transclude(scope, function(clone) {
        // Inject the element somewhere in the page
      });
      scope.$on('$destroy', function() {
        // Remove the element from the DOM
      });
    }
  };
});

There are a few techniques that can be used to communicate the clone of the element to the new location.

  • Directly walk the DOM to inject the clone, jQuery-style.
  • Use require to pass the clone to another directive by calling its controller directive
  • Fire off the clone using an Angular event $emit or $broadcast. Another directive would be listening to this event and inject the clone.

I should admit, I've not used this technique for anything but a few tests, so there could be some consequences about this that I haven't encountered.