Asked  6 Months ago    Answers:  5   Viewed   45 times

I have a dataset of about 1000 items in-memory and am attempting to create a pager for this dataset, but I'm not sure on how to do this.

I'm using a custom filter function to filter the results, and that works fine, but somehow I need to get the number of pages out.

Any clues?

 Answers

61

Angular UI Bootstrap - Pagination Directive

Check out UI Bootstrap's pagination directive. I ended up using it rather than what is posted here as it has enough features for my current use and has a thorough test spec to accompany it.

View

<!-- table here -->

<pagination 
  ng-model="currentPage"
  total-items="todos.length"
  max-size="maxSize"  
  boundary-links="true">
</pagination>

<!-- items/page select here if you like -->

Controller

todos.controller("TodoController", function($scope) {
   $scope.filteredTodos = []
  ,$scope.currentPage = 1
  ,$scope.numPerPage = 10
  ,$scope.maxSize = 5;

  $scope.makeTodos = function() {
    $scope.todos = [];
    for (i=1;i<=1000;i++) {
      $scope.todos.push({ text:"todo "+i, done:false});
    }
  };
  $scope.makeTodos(); 

  $scope.$watch("currentPage + numPerPage", function() {
    var begin = (($scope.currentPage - 1) * $scope.numPerPage)
    , end = begin + $scope.numPerPage;

    $scope.filteredTodos = $scope.todos.slice(begin, end);
  });
});

I have made a working plunker for reference.


Legacy Version:

View

<!-- table here -->

<div data-pagination="" data-num-pages="numPages()" 
  data-current-page="currentPage" data-max-size="maxSize"  
  data-boundary-links="true"></div>

<!-- items/page select here if you like -->

Controller

todos.controller("TodoController", function($scope) {
   $scope.filteredTodos = []
  ,$scope.currentPage = 1
  ,$scope.numPerPage = 10
  ,$scope.maxSize = 5;

  $scope.makeTodos = function() {
    $scope.todos = [];
    for (i=1;i<=1000;i++) {
      $scope.todos.push({ text:"todo "+i, done:false});
    }
  };
  $scope.makeTodos(); 

  $scope.numPages = function () {
    return Math.ceil($scope.todos.length / $scope.numPerPage);
  };

  $scope.$watch("currentPage + numPerPage", function() {
    var begin = (($scope.currentPage - 1) * $scope.numPerPage)
    , end = begin + $scope.numPerPage;

    $scope.filteredTodos = $scope.todos.slice(begin, end);
  });
});

I have made a working plunker for reference.

Tuesday, June 1, 2021
 
kmunky
answered 6 Months ago
63

$ctrl is the view model object in your controller. This $ctrl is a name you choose (vm is another most common name), if you check your code you can see the definition as $ctrl = this;, so basically its the this keyword of the controller function.

So now if you are using $ctrl.latestMeasurement = 'someValue', then its like you are adding a property latestMeasurement to controller function.

Now how to use it in HTML?

To access the latestMeasurement property in HTML your code must have <h1>{{$ctrl.latestMeasurement}}</h1> (H1 tag is just an example.)

Here $ctrl is different from what I explained above on controller part. Here $ctrl is the value used for controllerAs property of the controller. But $ctrl is the default value of the controllerAs property, so your code may not have the controllerAs property defined, so Angular will take default value $ctrl in HTML.

This is where most people gets confused. So let me explain,

Assume in your new controller you have declared your this keyword to variable vm, and you set your controllerAs property to myCtrl, i.e;

controllerAs: 'myCtrl' while defining controller properties.

var vm = this; in your controller function.

In this case in js you have to use vm for setting values, and in HTML you have to use myCtrl. For example,

in JS controller function vm.test = 'Hello world';

in HTML <span ng-bind="myCtrl.test"></span>

The result Hello world will be displayed in your page.

Why $ctrl and not $scope?

The view model object model concept is introduced in AngularJS 1.5, it is actually part of migrating to Angular 2 where $scope no longer exsist. So in 1.5 they introduced new approch but did not removed $scope completely.

Hope the answer helped.

For basic Javascript concepts you can see http://javascriptissexy.com/16-javascript-concepts-you-must-know-well/

For more detailed AngularJS $ctrl concept you can see https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/

Monday, October 11, 2021
 
vlatkozelka
answered 2 Months ago
30

You can do this using a combination of:

  • A custom filter (to determine how many records to skip), and...
  • The built in limitTo filter (to limit the number of records to the desired page size)

1) First create the custom filter.

app.filter("startFrom", function thisFilter() {
  return function(input, index) {
    return input.slice(parseInt(index));
  };
});

The filter takes in an index which it goes on to use in the Array.prototype.slice() method. The slice() method slices the array at the given index and returns a new array containing all remaining objects. The filter returns the new array.

2) Use the custom filter and built-in limitTo filter in the ng-repeat directive.

<tr ng-repeat="queue in queueJob.QueueList | startFrom: queueJob.pageIndex | limitTo: 1">

Here we use the newly created startFrom custom filter passing it the queueJob.pageIndex property as the filter's index parameter. We pass the results of the startFrom filter onto the limitTo filter which reduces the number of records to 1.

Note: We have to use the pageIndex property on the queueJob itteration variable because this ng-repeat is contained within another ng-repeat and so a $scope.pageIndex variable would have been conflicted and subsequently overwritten.

3) Create next and previous buttons

<tr>
  <td colspan="5">
    <button class="btn" 
      ng-click="onPrevClicked(queueJob)"
      ng-disabled="isFirst(queueJob)">
      <span class="fa fa-chevron-left"></span>
      Prev
    </button>
    <button class="btn" 
      ng-click="onNextClicked(queueJob)"
      ng-disabled="isLast(queueJob)">
      Next
      <span class="fa fa-chevron-right"></span>
    </button>
    Page {{ queueJob.pageIndex + 1 }}
  </td>
</tr>

Here we use ng-click directives to invoke controller functions that increment/decrement the queueJob object's pageIndex property. We also use ng-disabled directives to prevent navigating next/previous if the user is on the first/last record.

4) Create the bindable functions in the controller

$scope.onPrevClicked = onPrevClicked;
$scope.onNextClicked = onNextClicked;
$scope.isFirst = isFirst;
$scope.isLast = isLast;

function onPrevClicked(obj) {
  if (!isFirst(obj)) obj.pageIndex--;
}

function onNextClicked(obj) {
  if (!isLast(obj)) obj.pageIndex++;
}

function isFirst(obj) {
  return obj.pageIndex === 0;
}

function isLast(obj) {
  return obj.pageIndex + 1 === obj.QueueList.length;
}

5) Initialise the pageIndex properties upfront

$scope.queuelist.forEach(function(obj) {
  obj.pageIndex = 0;
});

This initialised the pageIndex as a number that can be incremented and subsequently decremented.

Demo

CodePen: Using a custom filter to do pagination

Monday, October 18, 2021
 
RobertJoseph
answered 2 Months ago
29

I've been working with ng-table for a while. When I tried using variable names other than $data or data, it doesn't seem to work. So I suggest you should stick to using $data or data instead of any other variable names like dataset.

Here's a working Plunker.

UPDATE :

Looks like I missed to see what was really wrong in the OP's question. As Tyler Collier and yunus kala mentioned in the comments, you just have to use $data like <tr ng-repeat="user in $data"> instead of <tr ng-repeat="user in dataset">. And it doesn't matter if you use data or dataset in your controller code.

Friday, November 12, 2021
 
Jamey McElveen
answered 3 Weeks ago
86

You can use a function in the orderBy-clause like this:

<li data-ng-repeat="country in countries | filter:name | orderBy:'toString()'"> {{ country }}</li>
Saturday, November 13, 2021
 
Atomble
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share