This question is more complicated than might appear, so let's break it down.
What you are building is a directive that accepts a partial template - <div item-row item="item" />
- and that template uses (or linked against a scope with) an inner variable - item
- that is not defined in the outer scope by the user; its meaning is defined by your directive and your user "discovers" it by reading the documentation of your directive. I typically name such "magic" variables with a prefixed $
, e.g. $item
.
Step 1
Instead of passing a template as an HTML-as-string via attribute binding, pass it as contents and transclude that content. Transcluding allows you to bind the transcluded content against an arbitrary scope:
<foo>
<div>my item is: {{$item}}</div>
</foo>
.directive("foo", function(){
return {
scope: {},
transclude: true,
template: "<h1>I am foo</h1><placeholder></placeholder>",
link: function(scope, element, attrs, ctrls, transclude){
scope.$item = "magic variable";
transclude(scope, function(clonedContent){
element.find("placeholder").replaceWith(clonedContent);
});
}
};
});
The above will place the template <div>my item is: {{$item}}</div>
(could be any template you specify) where the directive foo
decides, and will link against a scope that has $item
defined.
Step 2
But the added complexity of your directive is that it uses ng-repeat
, which by itself accepts a template, and the template your directive receives needs to be used as a template of ng-repeat
.
With just the approach above, this would not work, since by the time link
runs, ng-repeat
will have already transcluded its own content before you had a chance to apply yours.
One way to address that is to manually $compile
the template of foo
instead of using the template
property. Prior to compiling, we will have a chance to place the intended template where needed:
.directive("foo", function($compile){
return {
scope: {},
transclude: true,
link: function(scope, element, attrs, ctrls, transclude){
scope.items = [1, 2, 3, 4];
var template = '<h1>I am foo</h1>
<div ng-repeat="$item in items">
<placeholder></placeholder>
</div>';
var templateEl = angular.element(template);
transclude(scope, function(clonedContent){
templateEl.find("placeholder").replaceWith(clonedContent);
$compile(templateEl)(scope, function(clonedTemplate){
element.append(clonedTemplate);
});
});
}
};
});
Demo