Reputation: 2048
I'm having an issue with using the ng-repeat directive in combination with my own custom directive.
HTML:
<div ng-app="myApp">
<x-template-field x-ng-repeat="field in ['title', 'body']" />
</div>
JS:
angular.module('myApp', [])
.directive('templateField', function () {
return {
restrict: 'E',
compile: function(element, attrs, transcludeFn) {
element.replaceWith('<input type="text" />');
}
};
});
See jSFiddle
The problem here is that nothing is replaced. What I'm trying to accomplish is an output of 2x input fields, with the 'x-template-field' tags completely replaced in the DOM. My suspicion is that since ng-repeat is modifying the DOM at the same time, this won't work.
According to this Stack Overflow question, the accepted answer seems to indicate this has actually worked in earlier versions of AngularJS (?).
While element.html('...') actually injects the generated HTML into the target element, I do not want the HTML as a child element of the template tag, but rather replace it completely in the DOM.
Basically, for the same reason as above, I don't want my generated HTML as a child element to the repeating tag. While it would probably work decently in my application, I would still feel like I've adapted my markup to fit Angular and not the other way around.
I haven't found any way to alter the HTML retrieved from the 'template' / 'templateUrl' properties. The HTML I want to inject is not static, it's dynamically generated from external data.
Probably. :-)
Any help is appreciated.
Upvotes: 17
Views: 19397
Reputation: 173
Your directive needs to run before ng-repeat
by using a higher priority, so when ng-repeat
clones the element it is able to pick your modifications.
The section "Reasons behind the compile/link separation" from the Directives user guide have an explanation on how ng-repeat works.
The current ng-repeat
priority is 1000, so anything higher than this should do it.
So your code would be:
angular.module('myApp', [])
.directive('templateField', function () {
return {
restrict: 'E',
priority: 1001, <-- PRIORITY
compile: function(element, attrs, transcludeFn) {
element.replaceWith('<input type="text" />');
}
};
});
Upvotes: 16
Reputation: 171690
Put your ng-repeat
in the template. You could modify attributes of element and accordingly in directive to determine if ng-repeat is needed, or what data to use inside the directive compiling
HTML(attribute):
<div ng-app="myApp" template-field></div>
JS:
angular.module('myApp', [])
.directive('templateField', function () {
return {
restrict: 'A',
template:'<input type="text" value="{{field}" ng-repeat="field in [\'title\',\'body\']" />'
};
});
DEMO: http://jsfiddle.net/GDfxd/3/
Also works as an element :
HTML(element):
<div ng-app="myApp" >
<template-field/>
</div>
JS
angular.module('myApp', [])
.directive('templateField', function () {
return {
restrict: 'E',
replace:true,
template:'<input type="text" value="{{field}}" ng-repeat="field in [\'title\',\'body\']" />'
};
});
DEMO: http://jsfiddle.net/GDfxd/3/
Upvotes: 3