AngularJS: "Шаблон для директивы должен иметь ровно один корневой элемент" при использовании тега "th" в шаблоне директивы
Я пытаюсь реализовать пользовательскую директиву sortBy
, чтобы сделать столбцы в таблице html сортируемой.
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);
}
}
};
});
Шаблон директивы:
<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>
Поэтому, когда я использую th
в качестве корневого тега шаблона директивы, я получаю сообщение об ошибке:
Error: [$compile:tplrt] Template for directive 'sortByDirective' must have exactly one root element. SortHeaderTemplate
но при изменении тегов th
на a
или span
все работает нормально.
Что я делаю неправильно?
Ответы
Ответ 1
Я ожидаю, что <th>
будет расплавлен в некоторой промежуточной точке, когда он оценивается вне контекста <tr>
(поместите этот шаблон в какую-нибудь случайную часть вашей веб-страницы, чтобы исчезнуть <th>
).
В вашей позиции я использовал бы <div>
в шаблоне, изменил бы sort-by-directive
на директиву типа "A" и использовал бы <th sort-by-directive>...</th>
, как и раньше, без replace: true
.
Ответ 2
Я встречал такие странности, как элементы директивы и таблицы. См. issue, например. Попробуйте обернуть ваш шаблон тегом div
или используйте replace:false
.
Ответ 3
Это не ваше дело, но у меня была такая же проблема, потому что у моего кода были комментарии html до и после разметки шаблона, например:
<!-- Foo Widget -->
<div class="foo-widget">[...]</div>
<!-- end:: Foo Widget -->
Я избавился от комментариев и вуаля - проблема решена.
Ответ 4
Эта ошибка также может быть вызвана тем фактом, что в шаблоне директивы вам необходимо иметь элемент упаковки для всех ваших тегов. Шаблон вашей директивы не может быть только:
<nav></nav>
<div></div>
Это должно быть:
<div>
<nav></nav>
<div></div>
</div>
Ответ 5
Я получил эту ошибку, когда использовал свойство template
определения директивы, когда я должен был использовать templateUrl
, если это кому-то помогает.
Ответ 6
Как заявлено другими: это потому, что ваш браузер игнорирует TH, прежде чем он будет помещен внутри таблицы. Мой предпочтительный способ исправить это - изменить директиву на директиву атрибута и добавить его в TH в таблице.
Директива выглядит следующим образом:
.directive('sortByDirective', function () {
return {
templateUrl: 'SortHeaderTemplate',
restrict: 'A',
transclude: true,
replace: false,
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);
}
}
};
});
Настройка на вашей странице выглядит следующим образом:
<th sort-by-directive
ng-repeat="header in headers"
onsort="onSort"
sortdir="filterCriteria.sortDir"
sortedby="filterCriteria.sortedBy"
sortvalue="{{ header.value }}">{{ header.title }}
</th>
Ответ 7
i возникает следующая ошибка:
Error: [$compile:tplrt] http://errors.angularjs.org/1.2.6/$compile/tplrt?p0=stockWidget&p1=stock.html.
Я обойду, удалив commement в самом верху файла шаблона.
replace устаревает с угловым 1.3 вперёд, следующий релиз полностью удалит его, лучше не использовать ключ замены.
Ответ 8
Я столкнулся с проблемой пару раз, и в большинстве случаев это может быть то, что вы не обертываете свои элементы под одним элементом, например
<div>
<div... </div>
</div>
Но был один случай, когда вы получаете эту ошибку, когда путь к шаблону неверен. Поэтому, пожалуйста, проверьте правильность ссылок на шаблон.
Ответ 9
Какую версию angular вы используете?
Была ошибка для чего-то похожего на вашу проблему, которая была исправлена в 1.2.13 1.3 Beta 1 commit link
https://github.com/angular/angular.js/issues/1459
Ответ 10
Я знаю, что это старо, но есть другое решение.
Я тоже столкнулся с этой проблемой и не поверил всем этим решениям.
получается, по какой-то странной причине, что эта ошибка возникает и в случае, если в "templateUrl" есть опечатка - если angular не может найти файл html по данному пути - вы получите то же самое ", должен иметь ровно одну ошибку корневого элемента.
так что исправление templateUrl исправило ошибку для меня.
надеюсь, что это поможет любому в будущем.