web-dev-qa-db-fra.com

AngularJS ng-repeat sans élément HTML

J'utilise actuellement ce morceau de code pour rendre une liste:

<ul ng-cloak>
    <div ng-repeat="n in list">
        <li><a href="{{ n[1] }}">{{ n[0] }}</a></li>
        <li class="divider"></i>
    </div>
    <li>Additional item</li> 
</ul>

Cependant, le <div> L'élément provoque des défauts de rendu très mineurs sur certains navigateurs. J'aimerais savoir s'il existe un moyen de faire la répétition ng sans le conteneur div ou une méthode alternative pour obtenir le même effet.

90
nehz

Comme Andy Joslin a déclaré qu'ils travaillaient sur des répétitions de commandes basées sur des commentaires mais apparemment, il y avait trop de problèmes de navigateur . Heureusement, AngularJS 1.2 ajoute la prise en charge intégrée permettant de répéter sans ajouter d’éléments enfants avec les nouvelles directives ng-repeat-start et ng-repeat-end.

Voici un petit exemple pour ajouter pagination Bootstrap :

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>
  <li ng-repeat-start="page in [1,2,3,4,5,6]"><a href="#">{{page}}</a></li>
  <li ng-repeat-end class="divider"></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

Un exemple complet de travail peut être trouvé ici .

John Lindquist a également un tutoriel vidéo à ce sujet sur son excellente page egghead.io .

103
jmagnusson

KnockoutJS syntaxe de liaison sans conteneur

Veuillez en garder une seconde: KnockoutJS offre une option extrêmement pratique consistant à utiliser une syntaxe de liaison sans conteneur pour sa liaison foreach, comme indiqué dans la note 4 de la documentation de liaison foreach. http://knockoutjs.com/documentation/foreach-binding.html

Comme l'illustre l'exemple de la documentation Knockout, vous pouvez écrire votre liaison dans KnockoutJS comme ceci:

<ul>
    <li class="header">Header item</li>
    <!-- ko foreach: myItems -->
        <li>Item <span data-bind="text: $data"></span></li>
    <!-- /ko -->
</ul>

Je pense qu’il est plutôt regrettable que AngularJS ne propose pas ce type de syntaxe.


Angular's ng-repeat-start et ng-repeat-end

Dans la manière AngularJS de résoudre ng-repeat _ problèmes, les exemples que je rencontre sont du type jmagnusson posté dans sa réponse (utile).

<li ng-repeat-start="page in [1,2,3,4,5]"><a href="#">{{page}}</a></li>
<li ng-repeat-end></li>

Ma pensée initiale en voyant cette syntaxe est: vraiment? Pourquoi Angular oblige-t-il tout ce balisage supplémentaire pour lequel je ne veux rien avoir à faire et qui est tellement plus facile dans Knockout? ng-repeat-start et ng-repeat-end sur des balises distinctes?


Une façon plus propre d'utiliser ng-repeat-start et ng-repeat-end

Après enquête sur l'assertion de hitautodestruct, ajout de ng-repeat-end sur une balise séparée correspond exactement à ce que je voudrais ne pas faire dans la plupart des cas, car il génère des éléments totalement inutilisables: dans ce cas, <li> articles ne contenant rien. Bootstrap 3 modélise les éléments de la liste pour donner l'impression que vous n'avez pas généré d'éléments superflus, mais lorsque vous inspectez le code HTML généré, ils sont présents.

Heureusement , vous n'avez pas besoin de faire beaucoup pour avoir une solution plus propre et une quantité plus courte de html: il suffit de mettre le ng-repeat-end déclaration sur la même balise HTML qui a le ng-repeat-start _ .

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>    
  <li ng-repeat-start="page in [1,2,3,4,5]" ng-repeat-end><a href="#"></a></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

Cela donne 3 avantages:

  1. moins de balises HTML à écrire
  2. les balises vides inutiles ne sont pas générées par Angular
  3. lorsque le tableau à répéter est vide, la balise avec ng-repeat ne sera pas généré, ce qui vous donnera le même avantage que la liaison sans conteneur de Knockout vous offre à cet égard

Mais il y a toujours un moyen plus propre

Après avoir passé en revue les commentaires de github sur ce problème pour Angular, https://github.com/angular/angular.js/issues/1891 ,
vous n’avez pas besoin d’utiliser ng-repeat-start et ng-repeat-end pour obtenir les mêmes avantages. Au lieu de cela, reprenons l'exemple de Jmagnusson, nous pouvons simplement aller:

<ul class="pagination">
  <li>
    <a href="#">&laquo;</a>
  </li>
  <li ng-repeat="page in [1,2,3,4,5,6]"><a href="#">{{page}}</a></li>
  <li>
    <a href="#">&raquo;</a>
  </li>
</ul>

Alors, quand utiliser ng-repeat-start et ng-repeat-end? Selon le documentation angulaire , à

... répétez une série d'éléments au lieu d'un seul élément parent ...

Assez parlé, montrez quelques exemples!

C'est suffisant; jsbin présente cinq exemples de ce qui se passe quand vous faites et quand vous n’utilisez pas ng-repeat-end sur la même étiquette.

http://jsbin.com/eXaPibI/1/

30
mg1075

ngRepeat peut ne pas suffire, mais vous pouvez combiner cela avec une directive personnalisée. Vous pouvez déléguer la tâche d'ajouter des éléments de division au code si un peu de jQuery ne vous dérange pas.

 <li ng-repeat="item in coll" so-add-divide="your exp here"></li>

Une directive aussi simple n'a pas vraiment besoin d'une valeur d'attribut mais peut vous donner beaucoup de possibilités, comme l'ajout conditionnel d'un diviseur en fonction de l'index, de la longueur, etc. ou de quelque chose de complètement différent.

6
orcun

J'ai eu récemment le même problème en ce sens que je devais répéter une collection arbitraire de plages et d'images. Avoir un élément autour d'eux n'était pas une option. Il existe une solution simple, mais créez une directive "null":

app.directive("diNull", function() {
        return {
            restrict: "E",
            replace: true,
            template: ""
        };
    });

Vous pouvez ensuite utiliser une répétition sur cet élément, où element.url pointe vers le modèle pour cet élément:

<di-null ng-repeat="element in elements" ng-include="element.url" ></di-null>

Cela répétera n'importe quel nombre de modèles différents sans aucun conteneur autour d'eux

Remarque: hmm, j'aurais peut-être juré à l'aveugle de supprimer l'élément di-null lors du rendu, mais le relire à nouveau ne résout pas ... toujours mes problèmes de mise en page bien ... curioser et curioser ...

3
Raphael Huerzeler

Il existe une restriction de directive de commentaire, mais ngRepeat ne la prend pas en charge (car elle nécessite un élément à répéter).

Je pense avoir vu l’équipe angular dire qu’elle travaillerait sur les répétitions de commentaires, mais je ne suis pas certaine. Vous devriez ouvrir un problème à ce sujet dans le référentiel. http: //github.com/angular/angular.js

1
Andrew Joslin

Il n'y a pas de moyen magique Angular). Si vous utilisez Bootstrap, vous pouvez le faire pour obtenir du code HTML valide. Vous obtiendrez alors le même effet que d'ajouter le paramètre li.divider.

Créer une classe:

span.divider {
 display: block;
}

Maintenant changez votre code en ceci:

<ul ng-cloak>
 <li div ng-repeat="n in list">
    <a href="{{ n[1] }}">{{ n[0] }}</a>
    <span class="divider"></span>
 </li>
 <li>Additional item</li>
</ul>
0

pour une solution qui fonctionne vraiment

html

<remove  ng-repeat-start="itemGroup in Groups" ></remove>
   html stuff in here including inner repeating loops if you want
<remove  ng-repeat-end></remove>

ajouter une directive angular.js

//remove directive
(function(){
    var remove = function(){

        return {    
            restrict: "E",
            replace: true,
            link: function(scope, element, attrs, controller){
                element.replaceWith('<!--removed element-->');
            }
        };

    };
    var module = angular.module("app" );
    module.directive('remove', [remove]);
}());

pour une brève explication,

ng-repeat se lie au <remove> élément et boucles comme il se doit, et comme nous avons utilisé ng-repeat-start/ng-repeat-end, il boucle un bloc de code HTML non seulement un élément.

alors la directive de suppression personnalisée place le <remove> début et fin des éléments avec <!--removed element-->

0
Clint