AngularJS: 'Template for directive must have exactly one root element' when using 'th' tag in directive template
Solution 1
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
.
Solution 2
I've encountered oddities like that with directive and table elements. See this issue for example. Try wrapping your template with div
tag or use replace:false
.
Solution 3
This isn't your case, but I had this very same issue because my code had html comments before and after the template markup, like so:
<!-- Foo Widget -->
<div class="foo-widget">[...]</div>
<!-- end:: Foo Widget -->
I got rid of the comments and voilá - problem solved.
Solution 4
This error can be also caused by the fact that you need to have a wrapping element for all your tags in the directive's template. Your directive's template can't be only:
<nav></nav>
<div></div>
It must be:
<div>
<nav></nav>
<div></div>
</div>
Solution 5
I got this error when I used the template
property of the directive definition when I should've been using templateUrl
if that helps anyone.
Andrei
Updated on March 23, 2021Comments
-
Andrei over 3 years
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
toa
orspan
tags everything works fine.What am I doing wrong?