Skip to content Skip to sidebar Skip to footer

How To Pass Ngrepeat "template" To A Ngdirective Using Transclude?

Demo: http://plnkr.co/edit/TiH96FCgOGnXV0suFyJA?p=preview I have a ng-directive called myDirective and within the directive template I have a list of li tags printed using ng-repea

Solution 1:

Transcluded contents are compiled against a child scope of your parent scope (also known as transclusion scope, but this is not the same as your directive's isolated scope). That being said, you can specify the template in your parent HTML (although it is a bit outside of the normal use case in angular) and manually compile it against your directive's isolated scope.

HTML

<bodyng-app="myApp"><divng-controller="myController as vm"><my-directivesource="vm.source"><span>{{item.label}} and {{item.id}}</span></my-directive></div></body>

Notice that the inner HTML of my-directive references 'item' which must be defined in the directive's scope.

Directive

functiondirective($compile) {
    return {
        restrict: 'E',
        scope: {
            source: '='
        },
        compile: function(element, attr) {
          // in the compile phase, remove the contents // of element so that it is not compiled by angular.// We will be manually compiling it in the link function.var template = angular.element('<ul><li ng-repeat="item in source">' + element.html() + '</li></ul>');
           element.empty();

           // link functionreturnfunction(scope, element, attr) {
             // append the template
             element.append(template);

             // compile and link the template against the isolated scope.$compile(template)(scope);
           }              
        }          
    };
}

Demo Plunker

Solution 2:

Jeff, your transcludes are a little backwards.

Or, moreso, the way transcludes work is a little backward, compared to how you think they do.

If you have a transcluding directive, and you put content inside of it, the content is reading from the parent of the transclude directive, and not the directive itself.

For your example, assuming :

<divng-controller="parentController as parent"><transcluding-directive>
        {{ key }} {{ val }}
    </transcluding-directive></div>

There are two problems, here.

The first problem is that ng-transclude is a sibling to the content it transcludes. Both of them would use parent as their parent-scope. The transcluded content doesn't read data from inside of the transcluding directive. This is again that separation of concerns, thing; if the transcluding directive had the same property names as the content you were transcluding, that would overwrite the transcluded content, and cause all kinds of weird behaviour, so they're siblings.

For all intent and purpose, under the covers, it might behave like this:

<transcluding-directive></transcluding-directive><div>{{ transcludedContent }}</div>

Then, the content would be pulled up, and appended to the node found by transcludingDirective.querySelector("[ng-transclude"]).

That's really not the exact workings of it, but it is the result you get (short of you doing your own compiling/transcluding routines, in the directive).

The second error is a little more obvious, when you know the first error: {{ label }} and {{ id }} of vm are properties on vm's $scope object.

They don't exist on that $scope, and are therefore undefined, which is why you get '' + 'and' + '' out of your templates. You are creating an <li> for each of the items passed to the directive, but you are interpolating undefined and undefined for each of them.

The directive you've written should either be a specialized directive (one that knows how to build that exact kind of list),

<specific-list-makeritems="vm.list"></specific-list-maker>

or a general directive, which you feed the list into

<generic-drawer><ul><ling-repeat="item in vm.list">{{item.label}} {{item.id}}</li></ul></generic-drawer>

...it could even be a specific directive which knows how to feed more generic directives, inside of its template...

<specific-listitems="vm.list"></specific-list><!-- specific-list.html --><generic-drawer><generic-toggleng-repeat="item in items">{{ item.label }} {{ item.id }}</generic-toggle></generic-drawer>

This is the composition that Angular (and Polymer, and in the future, Web Components, themselves) lends itself well to.

As a simple example from a project that I've been working on, I've got elements that filter down, something like this:

<page-type-a></page-type-a><!-- page-type-a.html --><card-collectioncards="page.items"></card-collection><!-- card-collection.html --><header ><!-- ... header stuff --></header><cardng-repeat="card in cards"></card><!-- card.html --><header><h1>{{ title }}</h1></header><blockquote>{{ content }}</blockquote><cite>{{ author }}</cite><page-type-b></page-type-b><!-- page-type-b.html --><card-collectioncards="page.items"></card-collection>

Each component doing little more than its own job.

There are other ways of getting this to work (feeding in a "key" attribute and a "value" attribute, and functionally plucking the values out of each item in the list to compose your own internal list, for your ng-repeat... ...or preparsing the values from the transcluded content, prior to linking your $scope instance to the transcluding-directive's inner template, before inserting it into DOM...) ...but doing that, in this case is just about as crazy as it sounds.

Post a Comment for "How To Pass Ngrepeat "template" To A Ngdirective Using Transclude?"