AngularJS ng-repeat gestisce il caso elenco vuoto


377

Ho pensato che sarebbe stata una cosa molto comune, ma non sono riuscito a trovare come gestirlo in AngularJS. Diciamo che ho un elenco di eventi e voglio riprodurli con AngularJS, quindi è abbastanza facile:

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

Ma come gestisco il caso quando l'elenco è vuoto? Voglio avere una finestra di messaggio sul posto in cui l'elenco è con qualcosa come "Nessun evento" o simile. L'unica cosa che si avvicina è il ng-switchcon events.length(come posso verificare se vuoto quando un oggetto e non un array?), Ma è davvero l'unica opzione che ho?


4
@La risposta di Artem è buona (+1). Ecco una discussione di gruppo di Google che utilizza un filtro, per riferimento / confronto: groups.google.com/d/topic/angular/wR06cN5oVBQ/discussion
Mark Rajcok,

Risposte:


569

Puoi usare ngShow .

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

Vedi esempio .

Oppure puoi usare ngHide

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

Vedi esempio .

Per oggetto puoi testare Object.keys .


1
Infatti @ArtemAndreev. Quando "eventi" è un array vuoto, restituisce true anche se l'array è vuoto
Rob Juurlink

Penso che ci sia un problema con Object.keys: jsfiddle.net/J9b5z , come lo gestiresti ?
Dani,

5
nh-show ha funzionato nel mio caso ma non aggiorna lo stato quando inserisco un filtro e non viene restituito nulla. Inoltre l'oggetto viene visualizzato al primo caricamento e scompare quando si ripete il processo di ripetizione al caricamento della pagina.
dvdmn,

1
@Dani prova ad aggiungere una funzione al controller che esegue il test. È quindi possibile semplicemente invocare la direttiva con ng-hide="hasEvents()".
Mr. S

Sì grazie. Tuttavia, speravo che ci sarebbe stato un modo più elegante senza "inquinare" il controller.
Dani

370

E se vuoi usarlo con un elenco filtrato, ecco un trucco pulito:

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

3
Molto utile. Errore di battitura però con "filteredFragments".
Ravishi,

1
Dolce! L'espressione dentro ng-repeat sembra però strana. Qualche possibilità che potresti spiegarlo? Grazie!!
MK Safi,

7
@MKSafi, sta creando una nuova variabile sull'ambito chiamato filteredItemse impostando il suo valore su (items | filter:keyword)- in altre parole, l'array restituito dal filtro
AlexFoxGill

17
SÌ! Ninja plus points! Ciò consente di risparmiare angolare dalla valutazione di un filtro complesso due volte!
markmarijnissen,

2
Inoltre, sembrano esserci alcune limitazioni intorno a questo con più filtri, come "face in filteredFaces = faces|filter:{deleted: true} | orderBy:'text'ma sono d'accordo con tutti, questo è un trucco favoloso.
Fitter Man,

29

Potresti voler controllare la direttiva angular-ui ui-if se vuoi semplicemente rimuovere il uldal DOM quando l'elenco è vuoto:

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

1
Grazie. Sembra più pulito del semplice nasconderlo.
Prinzhorn,

@Mortimer: quindi in questo caso abbiamo bisogno di angular-ui?
Shibbir Ahmed,

puoi usarlo ng-hidesenza angular-ui, ma nasconderà semplicemente il nodo, non lo rimuoverà dall'albero DOM. Con la ui-ifdirettiva di angular-ui , rimuoverà il nodo DOM. Quindi, devi almeno aggiungere la ui-ifdirettiva dal codice angular-ui al tuo codice.
Mortimer

21
il più recente angolare ha ng-ifincluso!
markmarijnissen,

4
Si noti che ng-ifsta creando un nuovo ambito, dove ng-hidenon lo è. Ciò potrebbe causare comportamenti imprevisti.
Arnold Daniels,

29

Con le versioni più recenti di angularjs la risposta corretta a questa domanda è usare 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>

Questa soluzione non sfarfallerà quando l'elenco sta per essere scaricato, poiché l'elenco deve essere definito e con una lunghezza pari a 0 per la visualizzazione del messaggio.

Ecco un plunker per mostrarlo in uso: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview

Suggerimento: puoi anche mostrare un testo di caricamento o un filatore:

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

Questo è simile a @Konrad 'ktoso' Malawski ma leggermente più facile da ricordare.

Testato con Angolare 1.4


3
Intending-if='!filteredItems.length'
abrunet,

Come si fa con più filtri?
Jordash,

@Jordash Continua a inviarli item in items | filter: ... | filter: ...
Bernard,

Un bel ulteriore perfezionamento è<li ng-if="!filteredItems.length">
Matty J,

Questo è fantastico Ho usato un metodo molto più sporco prima comeitem in (filteredItems = (items | filter: someFilter))
Firze,

6

Ecco un approccio diverso utilizzando CSS anziché JavaScript / AngularJS.

CSS:

.emptymsg {
  display: list-item;
}

li + .emptymsg {
  display: none;
}

markup:

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

Se l'elenco è vuoto, <li ng-repeat = "item in filteredItems">, ecc. Verrà commentato e diventerà un commento anziché un elemento li.


La domanda dice "Voglio avere una finestra di messaggio sul posto dove si trova l'elenco". Penso anche che sia svantaggioso separare la logica in un foglio di stile. Difficile da mantenere e chiedere problemi.
Prinzhorn,

1
@Prinzhorn, penso che usare CSS sia un vantaggio perché la logica è molto semplice e facile da mantenere, il CSS è riutilizzabile per altri elenchi e non si basa su JavaScript. Non sono necessari ascoltatori o osservatori aggiuntivi. Il messaggio potrebbe essere disegnato in modo da sembrare una scatola, non ho semplicemente tenuto la risposta semplice.
Miriam Salzer,

Pochi mesi dopo, scontato, ma concordo con Miriam, penso che questa risposta sia geniale.
Jon Combe,

2

Puoi usare questo 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

Puoi utilizzare la asparola chiave per fare riferimento a una raccolta sotto un ng-repeatelemento:

<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

di solito uso ng-show

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

dove variabile si definisce ad esempio

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

0

puoi usare ng-if perché questo non è render nella pagina html e non vedi il tuo tag html in 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>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.