Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I thought this would be a very common thing, but I couldn't find how to handle it in AngularJS. Let's say I have a list of events and want to output them with AngularJS, then that's pretty easy:

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

But how do I handle the case when the list is empty? I want to have a message box in place where the list is with something like "No events" or similar. The only thing that would come close is the ng-switch with events.length (how do I check if empty when an object and not an array?), but is that really the only option I have?

share|improve this question
1  
@Artem's answer is good (+1). Here's a google group discussion that uses a filter, for reference/comparison: groups.google.com/d/topic/angular/wR06cN5oVBQ/discussion – Mark Rajcok Sep 10 '12 at 15:49
up vote 498 down vote accepted

You can use ngShow.

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

See example.

Or you can use ngHide

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

See example.

For object you can test Object.keys.

share|improve this answer
1  
@shibbir It is test whether events defined. See jsfiddle.net/BXRPE. – Artem Andreev Mar 3 '13 at 17:04
1  
Indeed @ArtemAndreev. When "events" is an empty array, it returns true even though the array is empty – Rob Juurlink May 15 '13 at 12:33
    
I think there's a problem with Object.keys: jsfiddle.net/J9b5z, how would you handle this? – Dani Jun 10 '13 at 20:34
4  
nh-show worked id my case but it doesnt update the state when I put a filter in and nothing returned. Also the object appears on first load and disappears when the repeat process done on page load. – dvdmn Jun 13 '13 at 12:54
1  
@Dani try adding a function to your controller that performs the test. You can then just invoked the directive with ng-hide="hasEvents()". – Mr. S Aug 23 '13 at 20:23

And if you want to use this with a filtered list here's a neat trick:

<ul>
    <li ng-repeat="item in filteredItems  = (items | filter:keyword)">
        ...
    </li>
</ul>
<div ng-hide="filteredItems.length">No items found</div>
share|improve this answer
3  
Very useful. Typo though with "filteredFragments". – ravishi Sep 4 '13 at 20:26
11  
Great little trick, thank you – AlexFoxGill Oct 30 '13 at 11:25
7  
@MKSafi, it is creating a new variable on the scope called filteredItems and setting its value to (items | filter:keyword) - in other words, the array returned by the filter – AlexFoxGill Jan 14 '14 at 16:26
15  
YES! Ninja plus points! This saves angular from evaluating a complex filter twice! – markmarijnissen Mar 19 '14 at 19:40
5  
better than accepted answer, thanx. – Mohammad Walid Nov 10 '14 at 1:07

You might want to check out the angular-ui directive ui-if if you just want to remove the ul from the DOM when the list is empty:

<ul ui-if="!!events.length">
    <li ng-repeat="event in events">{{event.title}}</li>
</ul>
share|improve this answer
1  
Thanks. Feels cleaner than just hiding it. – Prinzhorn Dec 2 '12 at 8:46
    
@Mortimer: so in this case do we need angular-ui? – Shibbir Ahmed Mar 5 '13 at 12:27
    
you can use ng-hide without angular-ui, but it will just hide the node, it won't remove it from the DOM tree. With angular-ui's ui-if directive, it will remove the DOM node. So, you need to at least add the ui-if directive from the angular-ui code to your own code. – Mortimer Mar 5 '13 at 13:11
19  
newest angular has ng-if included! – markmarijnissen Mar 19 '14 at 19:41
3  
Note that ng-if is creating a new scope, where ng-hide isn't. This might cause unexpected behavior. – Jasny - Arnold Daniels Feb 18 '15 at 14:57

With the newer versions of angularjs the correct answer to this question is to use 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>

This solution will not flicker when the list is about to download either because the list has to be defined and with a length of 0 for the message to display.

Here is a plunker to show it in use: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview

share|improve this answer
    
it's helped me thks – JoDiii Feb 6 '15 at 4:14
<ul>
    <li ng-repeat="item in items | filter:keyword as filteredItems">
        ...
    </li>
    <li ng-if="filteredItems.length===0">
        No items found
    </li>
</ul>

This is similar to @Konrad 'ktoso' Malawski but slightly easier to remember.

Tested with Angular 1.4

share|improve this answer
3  
You mean ng-if='!filteredItems.length' – abrunet Oct 19 '15 at 16:21
    
yes. I've corrected the code – Alkaline Oct 20 '15 at 3:15
    
How do you do this with multiple filters? – Jordash May 19 '16 at 20:22
    
@Jordash Just keep piping them item in items | filter: ... | filter: ... – Alkaline May 19 '16 at 23:59
    
A nice, further refinement is <li ng-if="!filteredItems.length"> – Matty J Nov 3 '16 at 0:18

Here's a different approach using CSS instead of 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>

If the list is empty, <li ng-repeat="item in filteredItems">, etc. will get commented out and will become a comment instead of a li element.

share|improve this answer
    
Question says "I want to have a message box in place where the list is". I also think it's disadvantageous to separate the logic into s stylesheet. Hard to maintain and asking for trouble. – Prinzhorn Jan 10 '16 at 9:19
    
@Prinzhorn, I think using CSS is an advantage because the logic is very simple and easy to maintain, the CSS is reusable for other lists, and it doesn't rely on JavaScript. No additional listeners or watchers are needed. The message could be styled to look like a box, I just didn't to keep the answer simple. – Miriam Salzer Jan 11 '16 at 5:51
    
A few months late, granted, but I agree with Miriam, I think this answer is genius. – Jon Combe Nov 25 '16 at 6:45
    
This is the only one that worked for me. Fantastic. Thank you! – Siyah Dec 24 '16 at 20:41

You can use this 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>
share|improve this answer

i usually use ng-show

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

where variable you define for example

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

you can use ng-if because this is not render in html page and you dont see your html tag 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>
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.