48

I'm trying to limit my result sets to a fixed number. I can use limitTo with ng-repeat, but this limits items regardless of their current visibility and removes items from the DOM. I want to limit to a number of visible items while keeping everything in the DOM.

Here is the current code that I have. My goal is to always show no more than 50 items in the list even though items contains 500 items.

<div ng-repeat="item in items | limitTo: 50">
  <div ng-show="item.visible">
    <p>item.id</p>
  </div>
</div>

This will initially limit to 50 items, but if I filter the list (by modifying item.visible on some items), the list never shows items in the range of 50 - 500 and instead displays less than 50 items. What's the right way to limit an ng-repeat so that it only counts visible items towards the limit restriction?

Bill
  • 25,119
  • 8
  • 94
  • 125

4 Answers4

72

You can use:

<div ng-repeat="item in items | filter:{visible: true} | limitTo: 50">
    <p>{{item.id}}</p>
</div>

filter:{visible: true} will return a list of all visible items

You can take a look at the angularjs docu for more information on the filter filter. http://docs.angularjs.org/api/ng.filter:filter

bekite
  • 3,444
  • 2
  • 23
  • 31
  • 1
    This isn't the same thing since filters remove items from the DOM (like ng-if), instead of just modifying visibility (like ng-show). I'm looking for a solution that works with ng-show. – Bill Oct 26 '13 at 00:06
  • What is the reason you want to keep hidden elements in the DOM? – bekite Oct 26 '13 at 00:19
  • Constantly adding and removing them is slow. With ng-show the experience for filtering is instantaneous, with ng-if there is a slight hiccup before the updated results are shown. – Bill Oct 26 '13 at 00:35
  • I've created a plunker. http://plnkr.co/edit/TwdanjywAzUN4Oqcn06h?p=preview Could you please show me what you mean by "slight hiccup before the updated results are shown". You are right adding and removing elements from the dom is slower than showing/hiding them. – bekite Oct 26 '13 at 01:06
  • I updated plunker at http://plnkr.co/edit/JGYtnlb4UScemQ8hal1R?p=preview to have 'sort' and 'filter' functionality which is what I'm doing with my list. However, I can't get plunker to work on my mobile device to see if it actually demonstrates the lag I'm seeing... basically on a Windows 8 phone I get about 50ms of delay using ng-if and basically no delay using ng-show. – Bill Oct 26 '13 at 02:35
  • Sorry, I didn't know you were testing the app on a mobile phone. You are right about dom manipulations beeing slow there. I've updated the plunker to use ng-show. The approach I use is very primitive, not tested and maybe even slower that using filters. Its more of giving you some ideas on how I would try to solve this problem. http://plnkr.co/edit/g2KoyNN1Bs1M3NXJCaKB?p=preview (needs a lot of refactoring) – bekite Oct 26 '13 at 05:01
  • Thanks, guess I was hoping there was a cleaner solution but I'll do some testing to see if I can get it fast enough using this technique. Appreciate the help. – Bill Oct 26 '13 at 17:37
  • @Bill For what it's worth, you might try using the `track by` attribute in ngRepeat. You could do `track by item.id`, so that Angular might not have to rebuild all of the dom nodes when the order changes. It might speed things up a bit. –  Mar 06 '14 at 15:41
16

It is also possible to do it this way:

<div ng-repeat="item in items" ng-show="$index<50">
    <p>item.id</p>
</div>
Kostyantyn
  • 5,041
  • 3
  • 34
  • 30
  • 3
    This method physically puts the HTML in place. If you have 2000 records, that's 2000 divs dropped into your HTML but not seen. `ng-if` is slightly better in that it would dump comments instead of html, but it would still be better to just use the limitTo so it doesn't print extra content to the document – James Gray Feb 12 '17 at 00:09
1

There are a couple of approaches, maybe the most reusable is for you to create your own 'visible' custom filter which looks for visible attribute on your items. Then you could chain them.

<div ng-repeat="item in items | visible | limitTo: 50">

Here's a SO link to create custom filters

Community
  • 1
  • 1
Dan Doyon
  • 6,710
  • 2
  • 31
  • 40
  • Is there a solution that doesn't remove items from the DOM? I'm looking for something that works with ng-show. – Bill Oct 26 '13 at 00:10
1

You can use ng-if with $index to specify DOM display. Still generates ng-if comments but doesn't load the object so much improved performance noticed.

<div ng-init="your.objects={{},{},{}}; your.max=10">
  <div ng-repeat="object in your.objects" ng-if="$index<your.max">
    {{object}}
  </div>
</div>
irth
  • 1,696
  • 2
  • 15
  • 24