AngularJS ng-repeat handle cas de liste vide


377

Je pensais que ce serait une chose très courante, mais je n'ai pas trouvé comment le gérer dans AngularJS. Disons que j'ai une liste d'événements et que je veux les sortir avec AngularJS, alors c'est assez simple:

<ul>
    <li ng-repeat="event in events">{{event.title}}</li>
</ul>

Mais comment gérer le cas lorsque la liste est vide? Je veux avoir une boîte de message en place où la liste est avec quelque chose comme "Aucun événement" ou similaire. La seule chose qui se rapprocherait est le ng-switchavec events.length(comment puis-je vérifier s'il est vide quand un objet et non un tableau?), Mais est-ce vraiment la seule option que j'ai?


4
@ La réponse d'Artem est bonne (+1). Voici une discussion de groupe Google qui utilise un filtre, pour référence / comparaison: groups.google.com/d/topic/angular/wR06cN5oVBQ/discussion
Mark Rajcok

Réponses:


569

Vous pouvez utiliser ngShow .

<li ng-show="!events.length">No events</li>

Voir l' exemple .

Ou vous pouvez utiliser ngHide

<li ng-hide="events.length">No events</li>

Voir l' exemple .

Pour objet, vous pouvez tester Object.keys .


1
En effet @ArtemAndreev. Lorsque "events" est un tableau vide, il retourne vrai même si le tableau est vide
Rob Juurlink

Je pense qu'il y a un problème avec Object.keys: jsfiddle.net/J9b5z , comment géreriez -vous cela?
Dani

5
nh-show a fonctionné id mon cas, mais il ne met pas à jour l'état quand j'ai mis un filtre et rien n'est retourné. De plus, l'objet apparaît au premier chargement et disparaît lorsque le processus de répétition effectué au chargement de la page.
dvdmn

1
@Dani essaie d'ajouter une fonction à votre contrôleur qui effectue le test. Vous pouvez alors simplement invoquer la directive avec ng-hide="hasEvents()".
M. S

Oui merci. Cependant, j'espérais qu'il y aurait une manière plus élégante sans "polluer" le contrôleur.
Dani

370

Et si vous souhaitez l'utiliser avec une liste filtrée, voici une astuce intéressante:

<ul>
    <li ng-repeat="item in filteredItems  = (items | filter:keyword)">
        ...
    </li>
</ul>
<div ng-hide="filteredItems.length">No items found</div>

3
Très utile. Typo cependant avec "filterFragments".
ravishi

1
Doux! L'expression à l'intérieur de ng-repeat semble cependant étrange. Avez-vous une chance de l'expliquer? Merci!!
MK Safi

7
@MKSafi, il crée une nouvelle variable sur la portée appelée filteredItemset définit sa valeur sur (items | filter:keyword)- en d'autres termes, le tableau renvoyé par le filtre
AlexFoxGill

17
OUI! Ninja plus de points! Cela évite angulaire d'évaluer deux fois un filtre complexe!
markmarijnissen

2
En outre, il semble y avoir des limites à cela avec plusieurs filtres, "face in filteredFaces = faces|filter:{deleted: true} | orderBy:'text'mais je suis d'accord avec tout le monde, c'est une astuce fabuleuse.
Fitter Man

29

Vous voudrez peut-être consulter la directive angular-ui ui-if si vous souhaitez simplement supprimer le uldu DOM lorsque la liste est vide:

<ul ui-if="!!events.length">
    <li ng-repeat="event in events">{{event.title}}</li>
</ul>

1
Merci. Se sent plus propre que de simplement le cacher.
Prinzhorn

@Mortimer: dans ce cas, avons-nous besoin d'angular-ui?
Shibbir Ahmed

vous pouvez utiliser ng-hidesans angular-ui, mais cela masquera simplement le nœud, il ne le supprimera pas de l'arborescence DOM. Avec la ui-ifdirective angular-ui , il supprimera le nœud DOM. Donc, vous devez au moins ajouter la ui-ifdirective du code angular-ui à votre propre code.
Mortimer

21
le plus récent angulaire a ng-ifinclus!
markmarijnissen

4
Notez que cela ng-ifcrée une nouvelle portée, où il ng-hiden'y en a pas. Cela peut provoquer un comportement inattendu.
Arnold Daniels

29

Avec les nouvelles versions d'angularjs, la bonne réponse à cette question est d'utiliser ng-if:

<ul>
  <li ng-if="list.length === 0">( No items in this list yet! )</li>
  <li ng-repeat="item in list">{{ item }}</li>
</ul>

Cette solution ne scintillera pas non plus lorsque la liste est sur le point d'être téléchargée car la liste doit être définie et d'une longueur de 0 pour que le message s'affiche.

Voici un plongeur pour le montrer en cours d'utilisation: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview

Conseil: vous pouvez également afficher un texte de chargement ou une double flèche:

  <li ng-if="!list">( Loading... )</li>

23
<ul>
    <li ng-repeat="item in items | filter:keyword as filteredItems">
        ...
    </li>
    <li ng-if="filteredItems.length===0">
        No items found
    </li>
</ul>

Ceci est similaire à @Konrad 'ktoso' Malawski mais légèrement plus facile à retenir.

Testé avec Angular 1.4


3
Vous voulez direng-if='!filteredItems.length'
abrunet

Comment faites-vous cela avec plusieurs filtres?
Jordash

@Jordash Continuez à les canaliser item in items | filter: ... | filter: ...
Bernard

Un raffinement agréable et supplémentaire est<li ng-if="!filteredItems.length">
Matty J

C'est bien. J'utilisais une méthode beaucoup plus sale avant commeitem in (filteredItems = (items | filter: someFilter))
Firze

6

Voici une approche différente en utilisant CSS au lieu de JavaScript / AngularJS.

CSS:

.emptymsg {
  display: list-item;
}

li + .emptymsg {
  display: none;
}

Balisage:

<ul>
    <li ng-repeat="item in filteredItems"> ... </li>
    <li class="emptymsg">No items found</li>
</ul>

Si la liste est vide, <li ng-repeat = "item in filtersItems">, etc. sera mis en commentaire et deviendra un commentaire au lieu d'un élément li.


La question dit "Je veux avoir une boîte de message à l'endroit où se trouve la liste". Je pense également qu'il est désavantageux de séparer la logique dans la feuille de style. Difficile à entretenir et à demander des ennuis.
Prinzhorn

1
@Prinzhorn, je pense que l'utilisation de CSS est un avantage car la logique est très simple et facile à maintenir, le CSS est réutilisable pour d'autres listes, et il ne repose pas sur JavaScript. Aucun écouteur ou observateur supplémentaire n'est nécessaire. Le message pourrait être conçu pour ressembler à une boîte, je n'ai simplement pas gardé la réponse simple.
Miriam Salzer

Quelques mois de retard, d'accord, mais je suis d'accord avec Miriam, je pense que cette réponse est géniale.
Jon Combe

2

Vous pouvez utiliser ce ng-switch:

<div ng-app ng-controller="friendsCtrl">
  <label>Search: </label><input ng-model="searchText" type="text">
  <div ng-init="filtered = (friends | filter:searchText)">
  <h3>'Found '{{(friends | filter:searchText).length}} friends</h3>
  <div ng-switch="(friends | filter:searchText).length">
    <span class="ng-empty" ng-switch-when="0">No friends</span>
    <table ng-switch-default>
      <thead>  
        <tr>
          <th>Name</th>
          <th>Phone</th>
        </tr>
      </thead>
      <tbody>
      <tr ng-repeat="friend in friends | filter:searchText">
        <td>{{friend.name}}</td>
        <td>{{friend.phone}}</td>
      </tr>
    </tbody>
  </table>
</div>

1

Vous pouvez utiliser un asmot-clé pour référencer une collection sous un ng-repeatélément:

<table>
    <tr ng-repeat="task in tasks | filter:category | filter:query as res">
        <td>{{task.id}}</td>
        <td>{{task.description}}</td>
    </tr>
    <tr ng-if="res.length === 0">
        <td colspan="2">no results</td>
    </tr>
</table>

0

j'utilise habituellement ng-show

<li ng-show="variable.length"></li>

où variable vous définissez par exemple

<div class="list-group-item" ng-repeat="product in store.products">
   <li ng-show="product.length">show something</li>
</div>

0

vous pouvez utiliser ng-if car ce n'est pas le rendu dans la page html et vous ne voyez pas votre balise html dans inspect ...

<ul ng-repeat="item in items" ng-if="items.length > 0">
    <li>{{item}}<li>
</ul>
<div class="alert alert-info">there is no items!</div>
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.