AngularJS ng-repeat behandelt leeren Listenfall

377

Ich dachte, das wäre eine sehr häufige Sache, aber ich konnte in AngularJS nicht finden, wie ich damit umgehen sollte. Angenommen, ich habe eine Liste von Ereignissen und möchte sie mit AngularJS ausgeben. Dann ist das ziemlich einfach:

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

Aber wie gehe ich mit dem Fall um, wenn die Liste leer ist? Ich möchte ein Meldungsfeld haben, in dem die Liste so etwas wie "Keine Ereignisse" oder ähnliches enthält. Das einzige, was nahe kommen würde, ist das ng-switchmit events.length(wie überprüfe ich, ob ein Objekt und kein Array leer ist?), Aber ist das wirklich die einzige Option, die ich habe?

Prinzhorn
quelle
4
@ Artems Antwort ist gut (+1). Hier ist eine Google-Gruppendiskussion, die einen Filter als Referenz / Vergleich verwendet: groups.google.com/d/topic/angular/wR06cN5oVBQ/discussion
Mark Rajcok

Antworten:

569

Sie können ngShow verwenden .

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

Siehe Beispiel .

Oder Sie können ngHide verwenden

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

Siehe Beispiel .

Für Objekte können Sie Object.keys testen .

Artem Andreev
quelle
1
In der Tat @ArtemAndreev. Wenn "Ereignisse" ein leeres Array ist, gibt es true zurück, obwohl das Array leer ist
Rob Juurlink
Ich denke, es gibt ein Problem mit Object.keys: jsfiddle.net/J9b5z , wie würden Sie damit umgehen?
Dani
5
nh-show hat in meinem Fall funktioniert, aber der Status wird nicht aktualisiert, wenn ich einen Filter eingefügt habe und nichts zurückgegeben wurde. Das Objekt wird auch beim ersten Laden angezeigt und verschwindet, wenn der Wiederholungsvorgang beim Laden der Seite ausgeführt wird.
DVD
1
@Dani versuchen Sie, Ihrem Controller eine Funktion hinzuzufügen, die den Test durchführt. Sie können dann einfach die Direktive mit aufrufen ng-hide="hasEvents()".
Herr S.
Ja dank. Ich hoffte jedoch, dass es einen eleganteren Weg geben würde, ohne den Controller zu "verschmutzen".
Dani
370

Und wenn Sie dies mit einer gefilterten Liste verwenden möchten, ist hier ein ordentlicher Trick:

<ul>
    <li ng-repeat="item in filteredItems  = (items | filter:keyword)">
        ...
    </li>
</ul>
<div ng-hide="filteredItems.length">No items found</div>
Konrad 'ktoso' Malawski
quelle
3
Sehr hilfreich. Tippfehler allerdings mit "filteredFragments".
Ravishi
1
Süss! Der Ausdruck in ng-repeat sieht allerdings seltsam aus. Gibt es eine Chance, dass du es erklären könntest? Vielen Dank!!
MK Safi
7
@MKSafi, es erstellt eine neue Variable auf dem aufgerufenen Bereich filteredItemsund setzt ihren Wert auf (items | filter:keyword)- mit anderen Worten, das vom Filter zurückgegebene Array
AlexFoxGill
17
JA! Ninja plus Punkte! Dies erspart Winkel bei der zweimaligen Bewertung eines komplexen Filters!
Markmarijnissen
2
Es scheint auch einige Einschränkungen mit mehreren Filtern zu geben, wie, "face in filteredFaces = faces|filter:{deleted: true} | orderBy:'text'aber ich stimme allen zu, dies ist ein fabelhafter Trick.
Fitter Man
29

Sie können die Angular-UI-Direktive überprüfen, ui-ifwenn Sie die nur ulaus dem DOM entfernen möchten, wenn die Liste leer ist:

<ul ui-if="!!events.length">
    <li ng-repeat="event in events">{{event.title}}</li>
</ul>
Mortimer
quelle
1
Vielen Dank. Fühlt sich sauberer an, als es nur zu verstecken.
Prinzhorn
@ Mortimer: Also brauchen wir in diesem Fall Angular-UI?
Shibbir Ahmed
Sie können ng-hideohne Angular-UI verwenden, aber der Knoten wird nur ausgeblendet und nicht aus dem DOM-Baum entfernt. Mit der ui-ifDirektive von angle-ui wird der DOM-Knoten entfernt. Sie müssen also mindestens die ui-ifDirektive aus dem Winkel-UI-Code zu Ihrem eigenen Code hinzufügen .
Mortimer
21
neueste eckige hat ng-ifenthalten!
Markmarijnissen
4
Beachten Sie, ng-ifdass ein neuer Bereich erstellt wird, wo dies ng-hidenicht der Fall ist. Dies kann zu unerwartetem Verhalten führen.
Arnold Daniels
29

Bei den neueren Versionen von anglejs lautet die richtige Antwort auf diese Frage 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>

Diese Lösung flackert auch nicht, wenn die Liste heruntergeladen werden soll, da die Liste definiert werden muss und eine Länge von 0 hat, damit die Nachricht angezeigt wird.

Hier ist ein Plunker, um die Verwendung zu zeigen: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview

Tipp: Sie können auch einen Ladetext oder einen Spinner anzeigen:

  <li ng-if="!list">( Loading... )</li>
Pylinux
quelle
23
<ul>
    <li ng-repeat="item in items | filter:keyword as filteredItems">
        ...
    </li>
    <li ng-if="filteredItems.length===0">
        No items found
    </li>
</ul>

Dies ähnelt @Konrad 'ktoso' Malawski, ist aber etwas leichter zu merken.

Getestet mit Angular 1.4

Bernard
quelle
3
Du meinstng-if='!filteredItems.length'
abrunet
Wie macht man das mit mehreren Filtern?
Jordash
@ Jordash Pfeife sie einfach weiter item in items | filter: ... | filter: ...
Bernard
Eine schöne, weitere Verfeinerung ist<li ng-if="!filteredItems.length">
Matty J
Das ist toll. Ich habe eine viel schmutzigere Methode verwendet, wie zum Beispielitem in (filteredItems = (items | filter: someFilter))
Firze
6

Hier ist ein anderer Ansatz, bei dem CSS anstelle von JavaScript / AngularJS verwendet wird.

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>

Wenn die Liste leer ist, wird <li ng-repeat = "item in filteredItems"> usw. auskommentiert und wird zu einem Kommentar anstelle eines li-Elements.

Miriam Salzer
quelle
Die Frage lautet "Ich möchte ein Meldungsfeld an der Stelle haben, an der sich die Liste befindet". Ich denke auch, dass es nachteilig ist, die Logik in ein Stylesheet zu unterteilen. Schwer zu pflegen und um Ärger zu bitten.
Prinzhorn
1
@Prinzhorn, ich denke, die Verwendung von CSS ist ein Vorteil, da die Logik sehr einfach und leicht zu warten ist, das CSS für andere Listen wiederverwendbar ist und nicht auf JavaScript basiert. Es werden keine zusätzlichen Zuhörer oder Beobachter benötigt. Die Nachricht könnte so gestaltet sein, dass sie wie eine Schachtel aussieht. Ich habe die Antwort einfach nicht einfach gehalten.
Miriam Salzer
Ein paar Monate zu spät, aber ich stimme Miriam zu, ich denke, diese Antwort ist genial.
Jon Combe
2

Sie können diesen ng-Schalter verwenden:

<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>
LukitaBrands
quelle
1

Mit dem asSchlüsselwort können Sie eine Sammlung unter einem ng-repeatElement referenzieren :

<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>
Damian Czapiewski
quelle
0

Ich benutze normalerweise ng-show

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

wo Variable Sie zum Beispiel definieren

<div class="list-group-item" ng-repeat="product in store.products">
   <li ng-show="product.length">show something</li>
</div>
Ezequiel García
quelle
0

Sie können ng-if verwenden, da dies nicht in der HTML-Seite gerendert wird und Sie Ihr HTML-Tag in inspect nicht sehen ...

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