AngularJS中ng-repeat如何处理空列表情况

378

我认为这应该是一个非常常见的事情,但是我在AngularJS中找不到如何处理它的方法。假设我有一个事件列表并希望使用AngularJS输出它们,那么这就很容易:

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

但是当列表为空时,我该怎么处理呢?我想在列表为空的地方放置一个消息框,内容类似于“无事件”之类的信息。唯一接近的选项是使用 ng-switchevents.length(如果不是数组而是对象,如何检查是否为空?),但这真的是我唯一的选择吗?


4
@Artem的回答很好(+1)。这是一个使用过滤器的Google小组讨论,供参考/比较:https://groups.google.com/d/topic/angular/wR06cN5oVBQ/discussion - Mark Rajcok
10个回答

571
你可以使用ngShow
<li ng-show="!events.length">No events</li>

查看示例

或者,您可以使用ngHide

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

请查看示例

对于对象,您可以测试Object.keys


1
确实@ArtemAndreev。 当“事件”是空数组时,即使该数组为空,它也会返回true。 - Rob Juurlink
5
nh-show 在我的情况下起作用,但是当我添加过滤器并且没有返回任何内容时,它不会更新状态。此外,该对象在首次加载时出现,当页面重新加载完成后就消失了。 - dvdmn
1
@Dani 试着在你的控制器中添加一个执行测试的函数。然后你可以使用 ng-hide="hasEvents()" 调用该指令。 - Mr. S
是的,谢谢。不过,我希望有一种更优雅的方式,而不会“污染”控制器。 - Dani
如果我在ng-repeat中使用大量的过滤器会怎样? - tom10271
显示剩余2条评论

372

如果您想在筛选列表中使用此功能,这里有一个不错的技巧:

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

3
非常有用。不过「filteredFragments」这个词有打错字。 - ravishi
1
太好了!ng-repeat内的表达式看起来很奇怪。你能解释一下吗?谢谢!! - M.K. Safi
7
@MKSafi,它在作用域中创建一个名为“filteredItems”的新变量,并将其值设置为(items | filter:keyword),换句话说,它是由过滤器返回的数组。 - Alex
17
是的!忍者加分!这样可以避免Angular评估复杂过滤器两次! - markmarijnissen
2
此外,似乎在使用多个过滤器时存在一些限制,比如`“face in filteredFaces = faces|filter:{deleted: true} | orderBy:'text'”,但我同意大家的看法,这是一个非常棒的技巧。 - Fitter Man
显示剩余3条评论

29

使用较新版本的angularjs,这个问题的正确答案是使用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>

当列表定义为空且长度为0时,此解决方案不会出现闪烁问题。

这里有一个Plunker以展示其用法:http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview

提示:您也可以显示加载文本或旋转图标:

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

29

如果您只想在列表为空时从DOM中删除

    ,则可以查看angular-ui指令ui-if

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

1
谢谢。感觉比只是隐藏它更清洁。 - Prinzhorn
@Mortimer:在这种情况下,我们需要angular-ui吗? - Shibbir Ahmed
你可以在没有angular-ui的情况下使用ng-hide,但它只会隐藏节点,而不会从DOM树中删除它。使用angular-ui的ui-if指令,它将删除DOM节点。 因此,您需要至少从angular-ui代码中添加ui-if指令到您自己的代码中。 - Mortimer
21
最新版的 Angular 已经包含了 ng-if 指令! - markmarijnissen
4
请注意,ng-if 创建了一个新的作用域,而 ng-hide 没有。这可能会导致意想不到的行为。 - Arnold Daniels

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

这与Konrad 'ktoso' Malawski类似,但稍微容易记住一些。

已经使用Angular 1.4测试过。


3
你的意思是 ng-if='!filteredItems.length' - abrunet
你如何使用多个过滤器来完成这个操作? - Jordash
@Jordash 只需继续将它们连接起来 item in items | filter: ... | filter: ... - Bernard
一个不错的进一步改进是 <li ng-if="!filteredItems.length"> - Matty J
太好了。我以前使用的方法比较糟糕,像这样:item in (filteredItems = (items | filter: someFilter)) - Firze

6
这里提供了一种使用CSS而不是JavaScript / AngularJS的不同方法。
CSS:
.emptymsg {
  display: list-item;
}

li + .emptymsg {
  display: none;
}

标记语言:

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

如果列表为空,<li ng-repeat="item in filteredItems">等将被注释掉,成为注释而不是li元素。

问题是“我想在列表所在的位置放置一个消息框”。我认为将逻辑分离到样式表中也是不利的。难以维护并会引发麻烦。 - Prinzhorn
1
@Prinzhorn,我认为使用CSS是一个优势,因为逻辑非常简单易于维护,CSS可重用于其他列表,并且不依赖JavaScript。不需要额外的监听器或观察者。消息可以被样式化成一个框,我只是为了保持答案简单而没有这样做。 - Miriam Salzer
几个月晚了,虽然如此,但我同意Miriam的观点,我认为这个答案是天才的。 - Jon Combe

2
您可以使用这个 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>

2
你可以使用 "as" 关键字来引用 ng-repeat 元素下的集合:

<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

我通常使用ng-show

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

其中变量你定义为例

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

0

你可以使用ng-if,因为它不会在HTML页面中呈现,所以你不会在检查中看到你的HTML标签...

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接