AngularJS:'指令模板必须只有一个根元素'当使用' th'指令模板中的标签

时间:2014-03-13 09:02:56

标签: javascript angularjs angularjs-directive

我正在尝试实现自定义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 个答案:

答案 0 :(得分:31)

我遇到了类似指令和表格元素的奇怪之处。例如,请参阅此issue。尝试使用div标记包装模板或使用replace:false

答案 1 :(得分:22)

这不是你的情况,但我遇到了同样的问题,因为我的代码在模板标记之前和之后都有html注释,如下所示:

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

我摆脱了评论和意见 - 问题解决了。

答案 2 :(得分:18)

我希望<th>在某个中间点被融化,当它在<tr>的上下文之外进行评估时(将该模板放入网页的某个随机部分以查看{{ 1}}消失)。

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

答案 3 :(得分:9)

此错误也可能是由于您需要为指令模板中的所有标记创建包装元素。您的指令的模板不能只是:

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

必须是:

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

答案 4 :(得分:6)

当我使用template时我使用templateUrl的{​​{1}}属性时,我遇到了这个错误,如果这有助于任何人。

答案 5 :(得分:3)

我知道这是旧的,但还有另一种解决方案。 我也遇到了这个问题,并且没有运气就尝试了上述所有解决方案。

原因出现了一些奇怪的原因,如果'templateUrl'中存在拼写错误,也会抛出此错误 - 如果angular无法通过给定路径找到html文件 - 你会得到相同的'必须有'正是一个根元素'错误。

所以 - 修复templateUrl为我修复了错误。

希望这有助于将来的任何人。

答案 6 :(得分: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>

答案 7 :(得分:2)

我几次遇到过这个问题,大部分时间都可能是你没有把你的元素包装在一个元素下面,如

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

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

答案 8 :(得分:1)

我遇到以下错误:

Error: [$compile:tplrt] http://errors.angularjs.org/1.2.6/$compile/tplrt?p0=stockWidget&p1=stock.html.

我在模板文件的顶部删除了纪念品。

使用angularjs 1.3 forward弃用

replace,下一个版本将完全删除它,最好不要使用replace键。

答案 9 :(得分:1)

Aaron's answer的一个更具体的情况是,当您认为时,您却拥有正确的模板路径,而实际上却没有:如documentation中所述templateUrl

URL相对于我们的index.html文件

就我而言,我已将模板目录放置在index.html下一级。当我将属性设置为templateUrl: '../templates/some-form.html'时,该路径是相对于脚本而不是相对于index.html的路径,从而导致相同的错误。

答案 10 :(得分:0)

您使用的是哪个版本的角色?

1.2.13 1.3 Beta 1 commit link

中修复了一个看起来像你的问题的错误

https://github.com/angular/angular.js/issues/1459

答案 11 :(得分:0)

我知道这是一个非常古老的答案和问题,但是我遇到了此错误,并通过将我的评论放在div标签中来解决。

之前:

    <!--You commented code-->
      <div>

      </div>

之后:

<div>
    <!--You commented code-->
</div>

答案 12 :(得分:0)

补充 Biljana 的答案,当您认为自己有正确的模板路径而实际上没有时,特别是 dos/mac/unix 系统中的大写/小写差异。

我的本​​地路径:

templateUrl: 'ng/ImageDnd/dropzone.tpl.html',

我的真实路径:

ng/ImageDnD/dropzone.tpl.html

注意 AnnotationsDnd 末尾的 D。

我的 Macbook 没有报错,但在 Linux 中部署时出错。