katerinkadar katerinkadar - 3 months ago 47
Javascript Question

ng-table v1.0.0: TypeError: Cannot read property 'page' of undefined

I trying to use angularjs ng-table from example:
http://4dev.tech/2015/08/tutorial-basic-datatable-sorting-filtering-and-pagination-with-angularjs-and-ng-table/



angular.module('ngTableTutorial', ['ngTable'])
.controller('tableController', function ($scope, $filter, NgTableParams) {

$scope.users = [{"id":1,"first_name":"Philip","last_name":"Kim","email":"pkim0@mediafire.com","country":"Indonesia","ip_address":"29.107.35.8"},
{"id":2,"first_name":"Judith","last_name":"Austin","email":"jaustin1@mapquest.com","country":"China","ip_address":"173.65.94.30"},
{"id":3,"first_name":"Julie","last_name":"Wells","email":"jwells2@illinois.edu","country":"Finland","ip_address":"9.100.80.145"},
{"id":4,"first_name":"Gloria","last_name":"Greene","email":"ggreene3@blogs.com","country":"Indonesia","ip_address":"69.115.85.157"},
{"id":50,"first_name":"Andrea","last_name":"Greene","email":"agreene4@fda.gov","country":"Russia","ip_address":"128.72.13.52"}];
$scope.usersTable = new NgTableParams({
page: 1,
count: 10
}, {
total: $scope.users.length,
getData: function ($defer, params) {
$scope.data = $scope.users.slice((params.page() - 1) * params.count(), params.page() * params.count());
$defer.resolve($scope.data);
}
});
});

<!DOCTYPE html>
<html ng-app="ngTableTutorial">
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.js"></script>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" media="screen">
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.css">
<script src="https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.js"></script>
<!-- <link href="app/resources/css/style.css" rel="stylesheet" type="text/css"/>
<script src="app/resources/js/app.js" type="text/javascript"></script>-->

</head>
<body>
<div ng-controller="tableController">
<table ng-table="usersTable" class="table table-striped">
<tr ng-repeat="user in data">
<td data-title="'Id'" >
{{user.id}}
</td>
<td data-title="'First Name'" >
{{user.first_name}}
</td>
<td data-title="'Last Name'" >
{{user.last_name}}
</td>
<td data-title="'e-mail'" >
{{user.email}}
</td>
<td data-title="'Country'">
{{user.country}}
</td>
<td data-title="'IP'" >
{{user.ip_address}}
</td>
</tr>
</table>
</div>
</body>
</html>





And get exception:
TypeError: Cannot read property 'page' of undefined

I think, it because ng-table go to new version 1.0.0. And now, this example is not working.
And I can’t figure out how to rewrite the example, so that it works with the new version ng-table?

Help me please.

UPD: Or can you just post standalone example, with ng-table 1.0.0, getdata, paging and filtration?

UPD: If delete $defer from getData params it is no help.
It is no throw out exception, but don't show data.
Snippet show the problem:

UPD 2016.08.16 1:15
I add line
$scope.data = $scope.users.slice((params.page() - 1) * params.count(), params.page() * params.count());

and now data show, but not filtering.
How rewrite snippet to filtering data?

UPD 2016.08.16 1:36:
Add string

counts: [2, 4, 6, 10, 20],


and

<tr ng-repeat="user in $data track by user.id">


And now paging and filtering is good.



angular.module('ngTableTutorial', ['ngTable'])
.controller('tableController', function($scope, $filter, NgTableParams) {

$scope.users = [
{ "id": 1, "first_name": "Philip", "last_name": "Kim", "email": "pkim0@mediafire.com", "country": "Indonesia", "ip_address": "29.107.35.8" },
{ "id": 2, "first_name": "Judith", "last_name": "Austin", "email": "jaustin1@mapquest.com", "country": "China", "ip_address": "173.65.94.30" },
{ "id": 3, "first_name": "Julie", "last_name": "Wells", "email": "jwells2@illinois.edu", "country": "Finland", "ip_address": "9.100.80.145" },
{ "id": 4, "first_name": "Gloria", "last_name": "Greene", "email": "ggreene3@blogs.com", "country": "Indonesia", "ip_address": "69.115.85.157" },
{ "id": 50, "first_name": "Andrea", "last_name": "Greene", "email": "agreene4@fda.gov", "country": "Russia", "ip_address": "128.72.13.52" }
];
$scope.usersTable = new NgTableParams({
page: 1,
count: 2
}, {
total: $scope.users.length,
counts: [2, 4, 6, 10, 20],
getData: function( params) {
params.total($scope.users.length);
$scope.data = $scope.users.slice((params.page() - 1) * params.count(), params.page() * params.count());
return $scope.data;

}
});
})

<html ng-app="ngTableTutorial">
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.js"></script>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet" media="screen">
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.css">
<script src="https://rawgit.com/esvit/ng-table/master/dist/ng-table.min.js"></script>
</head>
<body>
<div ng-controller="tableController">
<table ng-table="usersTable" class="table table-striped">
<tr ng-repeat="user in $data track by user.id">
<td data-title="'Id'" >
{{user.id}}
</td>
<td data-title="'First Name'" >
{{user.first_name}}
</td>
<td data-title="'Last Name'" >
{{user.last_name}}
</td>
<td data-title="'e-mail'" >
{{user.email}}
</td>
<td data-title="'Country'">
{{user.country}}
</td>
<td data-title="'IP'" >
{{user.ip_address}}
</td>
</tr>
</table>
</div>
</body>
</html>




Answer

There were some breaking changes from 0.8.x to the 1.0.0 release that are documented in the CHANGELOG file of the github repository here: https://github.com/esvit/ng-table/blob/master/CHANGELOG.md#breaking-changes

As @just.ru already pointed out, your problem will be caused by a change in the getData signature. In earlier versions, the first parameter was $defer, some deferred object as known from the $q service. This allowed for doing async calls and signaling that new data has arrived. With 1.0.0 the API has changed in a way that you can now either return data directly or return a promise for your data. The ng-table then handles everything for you.

So if your data is already available and you don't want to use server side filtering and sorting, you can either use the new dataset property like this:

$scope.users = [ /* your data... */ ];

assumed.

$scope.usersTable = new NgTableParams({
    // your config
  }, {
    dataset: $scope.users;
  }
);

Or you can handle the filtering on your own by implementing the getData method accordingly:

$scope.usersTable = new NgTableParams({
    // your config
  }, {
    getData: function(params) {
      params.total($scope.users.length);
      return $scope.users.slice((params.page() - 1) * params.count(), params.page() * params.count());
    }
  }
);

If your server supports filtering and paging, then you have to set some properties according to the response. The response must contain information about the total amount of elements matched by the query.

Assuming your JSON response looks like this:

{
   totalAmountOfMatchingItems: 33,
   itemsOfTheCurrentPage: [
     { /*... */ }
   ]
}

you can need to implement your getData accordingly:

$scope.usersTable = new NgTableParams({
    // your config
  }, {
    getData: function(params) {
      return $scope.backendApi.queryForResult(params).then(function(data) {
        params.total(data.totalAmountOfMatchingItems);
        return data.itemsOfTheCurrentPage;
      });
    }
  }
);

It is important to call the params.total() method so that ng-table knows how it must render the pagination.

UPDATE: When you are using the getData version, you also need to make sure to reference the correct value for the filtered items when iterating them. Before, you assigned the filtered items to $scope.data. This is now also handled by ng-table, which uses the $data property. So to fix your snippet, you also need to adapt the ng-repeat accordingly:

 <tr ng-repeat="user in $data track by user.id">
Comments