AngularJS ng-repeat uchwyt pusta wielkość liter listy

377

Myślałem, że będzie to bardzo powszechna sprawa, ale nie mogłem znaleźć sposobu, aby sobie z tym poradzić w AngularJS. Załóżmy, że mam listę zdarzeń i chcę wyprowadzić je za pomocą AngularJS, więc to całkiem proste:

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

Ale jak poradzić sobie ze sprawą, gdy lista jest pusta? Chcę mieć okno komunikatu w miejscu, w którym znajduje się lista z napisem „Brak zdarzeń” lub podobnym. Jedyne, co by się zbliżyło, to ng-switchz events.length(jak sprawdzić, czy pusty, gdy obiekt, a nie tablica?), Ale czy to naprawdę jedyna dostępna opcja?

Prinzhorn
źródło
4
Odpowiedź Artema jest dobra (+1). Oto dyskusja grupy google wykorzystująca filtr w celach informacyjnych / porównawczych: groups.google.com/d/topic/angular/wR06cN5oVBQ/discussion
Mark Rajcok

Odpowiedzi:

569

Możesz użyć ngShow .

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

Patrz przykład .

Lub możesz użyć ngHide

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

Patrz przykład .

Dla obiektu możesz przetestować Object.keys .

Artem Andreev
źródło
1
Rzeczywiście @ArtemAndreev. Gdy „zdarzenia” są pustą tablicą, zwraca wartość true, mimo że tablica jest pusta
Rob Juurlink
Myślę, że jest problem z Object.keys: jsfiddle.net/J9b5z , jak byś sobie z tym poradził?
Dani
5
nh-show działał w moim przypadku, ale nie aktualizuje stanu, gdy wstawiam filtr i nic nie zwraca. Obiekt pojawia się również przy pierwszym ładowaniu i znika, gdy proces powtarzania jest wykonywany przy ładowaniu strony.
dvdmn
1
@Dani spróbuj dodać funkcję do kontrolera, który wykonuje test. Następnie możesz po prostu wywołać dyrektywę za pomocą ng-hide="hasEvents()".
Pan S
Tak, dziękuję. Mam jednak nadzieję, że będzie bardziej elegancki sposób bez „zanieczyszczania” kontrolera.
Dani
370

A jeśli chcesz użyć tego z filtrowaną listą, oto fajna sztuczka:

<ul>
    <li ng-repeat="item in filteredItems  = (items | filter:keyword)">
        ...
    </li>
</ul>
<div ng-hide="filteredItems.length">No items found</div>
Konrad „ktoso” Malawski
źródło
3
Bardzo przydatne. Literówka z „filterFragments”.
ravishi
1
Słodkie! Jednak wyrażenie w powtórzeniu ng wygląda dziwnie. Czy jest szansa, że ​​mógłbyś to wyjaśnić? Dzięki!!
MK Safi,
7
@MKSafi, tworzy nową zmienną w wywoływanym zakresie filteredItemsi ustawia jej wartość na (items | filter:keyword)- innymi słowy, tablicę zwróconą przez filtr
AlexFoxGill
17
TAK! Ninja plus punkty! Oszczędza to kąta od dwukrotnej oceny złożonego filtra!
markmarijnissen
2
Poza tym wydaje się, że istnieją pewne ograniczenia związane z wieloma filtrami, "face in filteredFaces = faces|filter:{deleted: true} | orderBy:'text'ale zgadzam się ze wszystkimi, to fantastyczna sztuczka.
Fitter Man
29

Możesz chcieć sprawdzić dyrektywę angular-ui, ui-if jeśli chcesz tylko usunąć ulz DOM, gdy lista jest pusta:

<ul ui-if="!!events.length">
    <li ng-repeat="event in events">{{event.title}}</li>
</ul>
Mortimer
źródło
1
Dzięki. Czuje się czystszy niż tylko ukrywanie go.
Prinzhorn,
@Mortimer: więc w takim przypadku potrzebujemy interfejsu kątowego?
Shibbir Ahmed
możesz używać ng-hidebez interfejsu kątowego, ale po prostu ukryje on węzeł, nie usunie go z drzewa DOM. Dzięki ui-ifdyrektywie angular-ui usunie węzeł DOM. Musisz więc przynajmniej dodać ui-ifdyrektywę z kodu angular-ui do własnego kodu.
Mortimer
21
najnowszy kątownik ng-ifzawarł!
markmarijnissen
4
Zauważ, że ng-iftworzy nowy zakres, gdzie ng-hidenie ma. Może to spowodować nieoczekiwane zachowanie.
Arnold Daniels
29

W nowszych wersjach angularjs poprawną odpowiedzią na to pytanie jest 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>

To rozwiązanie nie będzie migotać, gdy lista ma zostać pobrana, ponieważ lista musi zostać zdefiniowana, a jej długość musi wynosić 0.

Oto plunker, aby pokazać go w użyciu: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview

Wskazówka: Możesz także wyświetlić ładujący się tekst lub pokrętło:

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

Jest to podobne do @Konrad „ktoso” Malawski, ale nieco łatwiejsze do zapamiętania.

Testowane z Angular 1.4

Bernard
źródło
3
Masz na myśling-if='!filteredItems.length'
abrunet,
Jak to zrobić z wieloma filtrami?
Jordash,
@Jordash Nadal je potokuj item in items | filter: ... | filter: ...
Bernard
Ładnym, dalszym dopracowaniem jest<li ng-if="!filteredItems.length">
Matty J
To jest świetne. Wcześniej stosowałem dużo brudniejszą metodęitem in (filteredItems = (items | filter: someFilter))
Firze,
6

Oto inne podejście przy użyciu CSS zamiast JavaScript / AngularJS.

CSS:

.emptymsg {
  display: list-item;
}

li + .emptymsg {
  display: none;
}

Narzut:

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

Jeśli lista jest pusta, <li ng-repeat = "item in filterItems"> itp. Zostanie skomentowany i stanie się komentarzem zamiast elementu li.

Miriam Salzer
źródło
Pytanie brzmi: „Chcę mieć okno komunikatu w miejscu, w którym znajduje się lista”. Myślę też, że rozdzielenie logiki na arkusz stylów jest niekorzystne. Trudne w utrzymaniu i proszące o kłopoty.
Prinzhorn,
1
@Prinzhorn, myślę, że korzystanie z CSS jest zaletą, ponieważ logika jest bardzo prosta i łatwa w utrzymaniu, CSS może być wykorzystywany do innych list i nie opiera się na JavaScript. Nie są potrzebne dodatkowe osoby słuchające ani obserwujące. Wiadomość może być stylizowana na pudełko, po prostu nie chciałem, aby odpowiedź była prosta.
Miriam Salzer
Kilka miesięcy spóźnienia, oczywiście, ale zgadzam się z Miriam, myślę, że ta odpowiedź jest genialna.
Jon Combe,
2

Możesz użyć tego przełącznika ng:

<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
źródło
1

Możesz użyć assłowa kluczowego, aby skierować kolekcję pod ng-repeatelement:

<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
źródło
0

zwykle używam ng-show

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

gdzie zmienna jest zdefiniowana na przykład

<div class="list-group-item" ng-repeat="product in store.products">
   <li ng-show="product.length">show something</li>
</div>
Ezequiel García
źródło
0

możesz użyć ng-if, ponieważ nie jest to renderowane na stronie HTML i nie widzisz swojego znacznika HTML w inspekcji ...

<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
źródło