Andrei Andrei - 4 months ago 20
AngularJS Question

AngularJS: 'Template for directive must have exactly one root element' when using 'th' tag in directive template

I'm trying to implement custom

sortBy
directive in order to make columns in html table sortable.

HTML:

<thead>
<tr>
<sort-by-directive
ng-repeat="header in headers"
onsort="onSort"
sortdir="filterCriteria.sortDir"
sortedby="filterCriteria.sortedBy"
sortvalue="{{ header.value }}">{{ header.title }}
</sort-by-directive>
</tr>
</thead>


JS:

angular.module('mainApp.directives').directive('sortByDirective', function () {

return {
templateUrl: 'SortHeaderTemplate',
restrict: 'E',
transclude: true,
replace: true,
scope: {
sortdir: '=',
sortedby: '=',
sortvalue: '@',
onsort: '='
},
link: function (scope, element, attrs) {
scope.sort = function () {
if (scope.sortedby == scope.sortvalue)
scope.sortdir = scope.sortdir == 'asc' ? 'desc' : 'asc';
else {
scope.sortedby = scope.sortvalue;
scope.sortdir = 'asc';
}
scope.onsort(scope.sortedby, scope.sortdir);
}
}
};
});


Directive Template:

<script id="SortHeaderTemplate" type="text/ng-template">
<th ng-click="sort(sortvalue)">
<span ng-transclude=""></span>
<span ng-show="sortedby == sortvalue">
<i ng-class="{true: 'sorting_asc', false: 'sorting_desc'}[sortdir == 'asc']"></i>
</span>
<span ng-show="sortedby != sortvalue">
<i ng-class="{true: 'sorting', false: 'sorting'}[sortdir == 'asc']"></i>
</span>
</th>
</script>


So when I use
th
as root tag of directive template I retrieve an error:

Error: [$compile:tplrt] Template for directive 'sortByDirective' must have exactly one root element. SortHeaderTemplate


but when I change
th
to
a
or
span
tags everything works fine.

What am I doing wrong?

Answer

I expect that the <th> is getting melted away at some intermediate point when it is evaluated outside the context of a <tr> (put that template into some random part of your webpage to see the <th> disappear).

In your position, I would use a <div> in the template, change sort-by-directive to an 'A' type directive, and use a <th sort-by-directive>...</th> as before, without replace: true.