AngularJS:在指令模板中使用'th'标签时,“指令模板必须只有一个根元素”的模板错误。

34

我正在尝试实现自定义的 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更改为aspan标签时,一切都可以正常工作。

我做错了什么?

13个回答

33

我曾经遇到过指令和表格元素的类似问题。例如,查看此问题。尝试使用div标签包装您的模板或使用replace:false


4
Diddo - 对我来说,“replace: true”是一种故障。 - Cody
2
+1,将“replace:true”更改为“replace:false”对我有用,而且我的“html”中甚至没有任何“th”、“tr”、“td”元素。 - fidev
使用类似这样的链接作为菜单,对我很有效:<li><a href ng-click="redirectTodiv('mentionList', $event)"><img title="Mentions List" src="images/postList.svg" title="" height="25" /><span class="navText">Mentions List</span></a></li> - onmyway

23

这不是你的情况,但我曾经遇到过相同的问题,因为我的代码在模板标记之前和之后都有html注释,就像这样:

<!-- Foo Widget -->
<div class="foo-widget">[...]</div>
<!-- end:: Foo Widget -->

我删除了评论,问题就解决了。


6
是的,这也是我的问题。谢谢! - Stone
这是我遇到过的最疯狂的Angular问题之一。非常感谢! - Nine Magics

21

我认为在没有包含在<tr>上下文中进行评估时,<th>标签在某个中间点被溶解掉了(将该模板放在网页的随机位置以查看<th>的消失)。

在您的位置上,我会在模板中使用<div>,将sort-by-directive更改为“A”类型指令,并像以前一样使用<th sort-by-directive>...</th>,但不使用replace: true


6
“replace: false” 对我而言有效。 - LAXIT KUMAR
我们能否使用 replace: true 和 restrict type E 来使其正常工作? - Heemanshu Bhalla

9

此错误可能是由于您需要在指令模板中为所有标记添加包装元素所致。您的指令模板不能只包含:

<nav></nav>
<div></div>

必须是:

<div>
 <nav></nav>
 <div></div>
</div>

2
在我的模板中添加包装元素解决了这个问题。感谢您的提示;0 - Andy Allison

6

当我应该使用templateUrl时,我错误地使用了指令定义的template属性,导致出现了这个错误。希望这能对大家有所帮助。


5
我知道这是老问题了,但还有另一种解决方法。 我也遇到过这个问题,尝试了所有以上的解决方案都没有用。
结果发现,由于某些奇怪的原因,如果' templateUrl '中存在拼写错误——如果angular无法通过给定路径找到html文件——你会得到相同的“必须有一个根元素”的错误。
所以——修复templateUrl对我来说解决了这个错误。
希望这能对未来的任何人有所帮助。

2
我遇到了这个问题很多次,大部分情况下可能是因为您没有将元素包装在一个元素下,例如


<div>
  <div... </div>
</div>

但有一次,当模板路径不正确时,您会遇到此错误。因此,请检查您是否正确引用了模板。


2

正如其他人所说:这是因为您的浏览器在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>

2
更具体的情况是Aaron的回答,当你认为你已经有了正确的模板路径,但实际上并没有:正如在文档中所述,对于templateUrl属性,URL相对于我们的index.html文件。在我的情况下,我将我的模板目录放在index.html的下一级。当我将属性设置为templateUrl: '../templates/some-form.html'时,路径是相对于脚本而不是index.html,导致相同的错误。

1
我遇到了以下错误:
Error: [$compile:tplrt] http://errors.angularjs.org/1.2.6/$compile/tplrt?p0=stockWidget&p1=stock.html.

我会通过删除模板文件的顶部注释来移除评论内容。
replace已被angularjs 1.3之后的版本弃用,下一个版本将完全删除它,最好不要使用replace关键字。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接