151

I find the AngularJS tutorials hard to understand; this one is walking me through building an app that displays phones. I’m on step 5 and I thought as an experiment I’d try to allow users to specify how many they’d like to be shown. The view looks like this:

<body ng-controller="PhoneListCtrl">

  <div class="container-fluid">
    <div class="row-fluid">
      <div class="span2">
        <!--Sidebar content-->

        Search: <input ng-model="query">
        How Many: <input ng-model="quantity">
        Sort by:
        <select ng-model="orderProp">
          <option value="name">Alphabetical</option>
          <option value="age">Newest</option>
        </select>

      </div>
      <div class="span10">
        <!--Body content-->

        <ul class="phones">
          <li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
            {{phone.name}}
            <p>{{phone.snippet}}</p>
          </li>
        </ul>

      </div>
    </div>
  </div>
</body>

I’ve added this line where users can enter how many results they want shown:

How Many: <input ng-model="quantity">

Here’s my controller:

function PhoneListCtrl($scope, $http) {
  $http.get('phones/phones.json').success(function(data) {
    $scope.phones = data.splice(0, 'quantity');
  });

  $scope.orderProp = 'age';
  $scope.quantity = 5;
}

The important line is:

$scope.phones = data.splice(0, 'quantity');

I can hard-code in a number to represent how many phones should be shown. If I put 5 in, 5 will be shown. All I want to do is read the number in that input from the view, and put that in the data.splice line. I’ve tried with and without quotes, and neither work. How do I do this?

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
Captain Stack
  • 3,572
  • 5
  • 31
  • 56

7 Answers7

348

Slightly more "Angular way" would be to use the straightforward limitTo filter, as natively provided by Angular:

<ul class="phones">
  <li ng-repeat="phone in phones | filter:query | orderBy:orderProp | limitTo:quantity">
    {{phone.name}}
    <p>{{phone.snippet}}</p>
  </li>
</ul>
app.controller('PhoneListCtrl', function($scope, $http) {
    $http.get('phones.json').then(
      function(phones){
        $scope.phones = phones.data;
      }
    );
    $scope.orderProp = 'age';
    $scope.quantity = 5;
  }
);

PLUNKER

AgDude
  • 1,167
  • 1
  • 10
  • 27
Stewie
  • 60,366
  • 20
  • 146
  • 113
  • 56
    It's worth pointing out - and saving someone else a few minutes - that if you're using "track by" it MUST be last after the filters. – stephan.com Jul 15 '15 at 03:25
  • 3
    Is there a way to get the number of available items when using filter and limitTo? I would like to use `limitTo` but provide a "load more" button to increase the limit. This should only be displayed if more records available. – Tim Büthe Nov 17 '15 at 13:54
  • What is `filter:query` ? – 0x777 Jan 28 '16 at 02:24
  • @defmx per the OP's question, `query` comes from `Search: ` – jusopi Mar 12 '16 at 03:28
47

A little late to the party, but this worked for me. Hopefully someone else finds it useful.

<div ng-repeat="video in videos" ng-if="$index < 3">
    ...
</div>
couzzi
  • 6,316
  • 3
  • 24
  • 40
  • 2
    I suspect this would be less efficient than using limitToFilter if it's a large array, because every item presumably has to be evaluated – rom99 Aug 05 '15 at 16:44
  • 3
    I had a scenario where I wanted to show 6 items from a backing array of much more. Using `ng-if="$index < 6"` allowed me to show only the first 6 while keeping the entire array searchable (I have a filter combined with a search field). – Jeroen Vannevel Sep 04 '15 at 13:56
  • It is not limit, it is hide the whole result if count more then 3. – fdrv Apr 01 '16 at 03:39
  • @Jek-fdrv - No, `ng-if`, in this case, will not render the DOM element of the repeater whose `$index` is greater than `3`. if `$index` in the repeater is `0, 1, or 2`, the condition is `true` and the DOM nodes are created. `ng-if` differs from `ng-hide` in the sense that elements are *not* added to the DOM. – couzzi Apr 01 '16 at 18:33
3

here is anaother way to limit your filter on html, for example I want to display 3 list at time than i will use limitTo:3

  <li ng-repeat="phone in phones | limitTo:3">
    <p>Phone Name: {{phone.name}}</p>
  </li>
Rizwan
  • 3,741
  • 2
  • 25
  • 22
2

store all your data initially

function PhoneListCtrl($scope, $http) {
  $http.get('phones/phones.json').success(function(data) {
    $scope.phones = data.splice(0, 5);
    $scope.allPhones = data;
  });

  $scope.orderProp = 'age';
  $scope.howMany = 5;
  //then here watch the howMany variable on the scope and update the phones array accordingly
  $scope.$watch("howMany", function(newValue, oldValue){
    $scope.phones = $scope.allPhones.splice(0,newValue)
  });
}

EDIT had accidentally put the watch outside the controller it should have been inside.

shaunhusain
  • 19,630
  • 4
  • 38
  • 51
1

This works better in my case if you have object or multi-dimensional array. It will shows only first items, other will be just ignored in loop.

.filter('limitItems', function () {
  return function (items) {
    var result = {}, i = 1;
    angular.forEach(items, function(value, key) {
      if (i < 5) {
        result[key] = value;
      }
      i = i + 1;
    });
    return result;
  };
});

Change 5 on what you want.

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
fdrv
  • 852
  • 1
  • 11
  • 21
0

Use limitTo filter to display a limited number of results in ng-repeat.

<ul class="phones">
      <li ng-repeat="phone in phones | limitTo:5">
        {{phone.name}}
        <p>{{phone.snippet}}</p>
      </li>
</ul>
-2

Another (and I think better) way to achieve this is to actually intercept the data. limitTo is okay but what if you're limiting to 10 when your array actually contains thousands?

When calling my service I simply did this:

TaskService.getTasks(function(data){
    $scope.tasks = data.slice(0,10);
});

This limits what is sent to the view, so should be much better for performance than doing this on the front-end.

Matt Saunders
  • 4,073
  • 7
  • 33
  • 47
  • Implementation of limitTo uses array.slice() anyway, any difference in size of array should have the same difference on performance as doing it yourself. https://github.com/angular/angular.js/blob/master/src/ng/filter/limitTo.js – rom99 Aug 05 '15 at 16:41
  • but limitTo does not actually limit data sent to the view, whereas doing it this way does. I tested this using console.log(). – Matt Saunders Aug 05 '15 at 17:07
  • 1
    Yes, what you are doing is exposing a new array to the view (I wouldn't really think of it as 'sending' anything anywhere). If you were only interested in the first 10 items in data, and data is not referenced anywhere else, doing it this way might reduce memory footprint (assuming data can be garbage collected). But if you are still keeping a reference to `data` around, this is no more efficient than using limitTo. – rom99 Aug 06 '15 at 09:00