web-dev-qa-db-fra.com

AngularJS: 'Le modèle de directive doit avoir exactement un élément racine' lors de l'utilisation de la balise 'th' dans le modèle de directive

J'essaie d'implémenter la directive sortBy personnalisée afin de rendre les colonnes de la table html triables.

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);
                }
            }
        };
    });

Modèle de directive:

<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>

Ainsi, lorsque j'utilise th comme balise racine du modèle de directive, je récupère une erreur:

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

mais quand je change les balises th en a ou span tout fonctionne bien.

Qu'est-ce que je fais mal?

30
Andrei

J'attends que le <th> est en train de fondre à un point intermédiaire quand il est évalué en dehors du contexte d'un <tr> (mettez ce modèle dans une partie aléatoire de votre page Web pour voir le <th> disparaître).

À votre place, j'utiliserais un <div> dans le modèle, modifiez sort-by-directive à une directive de type 'A' et utilisez un <th sort-by-directive>...</th> comme avant, sansreplace: true.

19
chbrown

J'ai rencontré des bizarreries comme ça avec des éléments de directive et de table. Voir ceci issue par exemple. Essayez d'encapsuler votre modèle avec la balise div ou utilisez replace:false.

32
haki

Ce n'est pas votre cas, mais j'ai eu ce même problème parce que mon code avait des commentaires html avant et après le balisage du modèle, comme ceci:

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

Je me suis débarrassé des commentaires et voilá - problème résolu.

22
darksoulsong

Cette erreur peut également être due au fait que vous devez avoir un élément d'habillage pour toutes vos balises dans le modèle de la directive. Le modèle de votre directive ne peut pas être uniquement:

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

Ce doit être:

<div>
 <nav></nav>
 <div></div>
</div>
9
eloone

J'ai eu cette erreur lorsque j'ai utilisé la propriété template de la définition de la directive alors que j'aurais dû utiliser templateUrl si cela aide quelqu'un.

6
racl101

Je sais que c'est vieux, mais il y a une autre solution. J'ai également rencontré ce problème et j'ai essayé toutes les solutions ci-dessus sans succès.

se révèle, pour une raison étrange, que cette erreur est également lancée dans le cas où il y a une faute de frappe dans le 'templateUrl' - si angular ne peut pas trouver le fichier html par le chemin donné - vous obtenir la même erreur "doit avoir exactement un élément racine".

donc - la fixation du templateUrl a corrigé l'erreur pour moi.

j'espère que cela aidera tout le monde à l'avenir.

3
Ariel Nahom

J'ai rencontré le problème plusieurs fois et la plupart du temps, il se peut que vous n'encapsuliez pas vos éléments sous un élément comme

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

Mais il y a eu une occasion où vous obtenez cette erreur lorsque le chemin du modèle n'est pas correct. Veuillez donc vérifier si vous faites référence au modèle correctement.

2
Giridhar Bandi

Comme indiqué par d'autres: c'est parce que votre navigateur ignore le TH avant qu'il ne soit placé dans le tableau. Ma façon préférée de résoudre ce problème est de changer la directive en une directive d'attribut et de l'ajouter à un TH dans le tableau.

La directive ressemble à ceci:

.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);
            }
        }
    };
});

Le définir sur votre page ressemble à ceci:

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

je rencontre l'erreur suivante:

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

Je me déplace en supprimant le commentaire en haut du fichier modèle.

replace est déconseillé avec angularjs 1.3 forward, la prochaine version le supprimera complètement, il est préférable de ne pas utiliser la clé de remplacement.

1
webon

Quelle version de angular utilisez-vous?

Il y avait un bug pour quelque chose ressemblant à votre problème qui a été corrigé dans 1.2.13 1.3 Beta 1 lien de validation

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

0
CCH