Pimgd Pimgd - 5 months ago 51
AngularJS Question

How to make ng-transclude behave like ng-include (in terms of scope)?

I'd like to transclude content as such that it acts as if I copy-pasted the content into the file where I write my

<div data-ng-transclude="">
. How do I do this?

I know I can use
ng-include
to include a template, and I can use script tags to define a template. But this clutters the template cache and pollutes the template namespace.

I want to do this so that I can have one (or more! That's the whole point) file in which I define the way I want to display my items,

<!-- list directive to show the items -->
<div data-item-list="" data-values="vm.items">

<!-- content to include to display list items -->
<div class="form-relation-picker-value" ng-bind="item.value.title"></div>
<div class="form-relation-picker-subtitle" ng-bind="item.value.subTitle"></div>
</div>


and one file in which I define the way the list's structure works.

<div class="list-container">
<div class="list-item"
data-ng-click="vm.select(item)"
data-ng-repeat="item in vm.items | orderBy : vm.orderBy"
data-selected="{{vm.isSelected(item)}}">

<div class="flex">
<div ng-transclude=""></div><!-- item display via transclude -->
<div class="grid-col flex-icon form-relation-picker-chrome-height-fix">
<div data-ng-show="vm.isSelected(item)" class="icon check"></div>
</div>
</div>
</div>
</div>





This works if I do something like this:

<div data-item-list="" data-values="vm.items" data-template-to-use="randomhash">
<script type="text/ng-template" id="randomhash">
<div class="form-relation-picker-value" ng-bind="item.value.title"></div>
<div class="form-relation-picker-subtitle" ng-bind="item.value.subTitle"></div>
</script>
</div>


with a list structure like so...

<div class="list-container">
<div class="list-item"
data-ng-click="vm.select(item)"
data-ng-repeat="item in vm.items | orderBy : vm.orderBy"
data-selected="{{vm.isSelected(item)}}">

<div class="flex">
<div data-ng-include="vm.templateToUse"></div>
<div class="grid-col flex-icon form-relation-picker-chrome-height-fix">
<div data-ng-show="vm.isSelected(item)" class="icon check"></div>
</div>
</div>
</div>
</div>


But, like I said, it clutters the template cache.

If I transclude the content, then it stops working, as the transcluded content is evaluated with the scope of the directive that contains the
<div data-item-list=""
. That is, "item" does not exist.

How can I make it so that the transcluded content is evaluated with the scope of the directive that is including the transcluded content?

Answer

What you need, is a template function that will extract the content of your template element (the element as it appears in your HTML, before Angular compiles it) and embed it into the directive's template.

As described in the docs, the template property of the DDO can be a function, in which case it receives the template element as an argument (among other things) and is expected to return the directive's template as a string.

You can use something like this:

.directive('itemList', function itemListDirective() {
  // DDO
  return {
    ...
    template: function itemListTmplFn(tElem) {
      var customContent = tElem.html();

      return '...' + customContent + '...';
    }
  };
})

Here is a simple demo that uses the .component() API (introduced in v1.5). There are some minor differences if you want to use a plain old .directive(), but you should be able to adapt it easily.

Comments