For some reason, my pagination is always resetting to 1 as the selected page, even though the result comes back from the server with the proper data in the results EG Records 31 - 45) and populate properly in the smart table. What could cause it to always reset the selected page in the pagination view to page 1? Is there a way to say what the selected page is?
Thanks in advance
Controller Method
$scope.getData = function (tableState) {
var pagination = tableState.pagination;
var start = pagination.start || 0;
var number = pagination.number || 10;
$scope.users = UserServicePaging.query({offset: start});
$scope.users.$promise
.then (function (result) { //success
$scope.users = result[0].results;
$scope.rowCollection = $scope.users;
$scope.displayedCollection = [].concat($scope.rowCollection);
tableState.pagination.numberOfPages = Math.ceil(parseInt(result[0].records.total)) / 15;
tableState.pagination.totalItemCount = Math.ceil(parseInt(result[0].records.total));
},
function (error) {//fail
})
.finally(function() {
});
}
Table Header:
<table st-table="displayedCollection" st-safe-src="rowCollection" st-pipe="getData" class="table table-striped">
Table Footer
<td colspan="5" class="text-center">
<div st-pagination="" st-items-by-page="itemsByPage" st-displayed-pages="10"></div>
</td>
Related
Im getting data in this format from api, but when i try binding it to table using angularjs it is creating empty space instead of values. Im also getting more then one table from some Api's please explain who to bind different datatables in different tables too. thanks
{"Table":
[{
"SchoolId":1,
"schoolname":"Microsoft",
"SCHOOLCODE":"29911583",
"WEBSITE":"JLR",
"USEREMAIL":"faucibus#aliquamiaculislacus.org",
"PHONE":"841-9331",
"ADDRESS1":"682-5760 Felis Street",
"ISACTIVE":0,
"PLANTYPE":3
}]
}
Angular Controller
SMSApp.factory('GetStudentService', function ($http) {
studobj = {};
studobj.getAll = function () {
var stud=[];
stud = $http({ method: 'Get', url: 'http://localhost:58545/api/Student?Studentid=1' }).
then(function (response) {
return response.data;
});
return stud;
};
return studobj;
});
SMSApp.controller('studentController', function ($scope, GetStudentService) {
$scope.msg = "Welcome from Controller";
GetStudentService.getAll().then(function (result) {
$scope.school = result;
console.log(result);
});
});
HTML Code
<tbody ng-controller="studentController">
<tr ng-repeat="schools in school track by $index">
<td>{{schools.SchoolId}}</td>
<td>{{schools.schoolname}}</td>
<td>{{schools.SCHOOLCODE}}</td>
<td>{{schools.WEBSITE}}</td>
<td>{{schools.USEREMAIL}}</td>
</tr>
</tbody>
WHAT I GET
Change in your Angular Controller :
SMSApp.controller('studentController', function ($scope, GetStudentService) {
$scope.msg = "Welcome from Controller";
GetStudentService.getAll().then(function (result) {
/********************* Changed Here ********************/
$scope.school = JSON.parse(result._body); // Or only JSON.parse(result)
$scope.school = $scope.school.table;
});
});
And your HTML Code :
<tbody ng-controller="studentController">
<tr ng-repeat="schools in school track by $index">
<td>{{schools.SchoolId}}</td>
<td>{{schools.schoolname}}</td>
<td>{{schools.SCHOOLCODE}}</td>
<td>{{schools.WEBSITE}}</td>
<td>{{schools.USEREMAIL}}</td>
</tr>
</tbody>
Naming the data school is confusing. Do instead:
GetStudentService.getAll().then(function (data) {
$scope.tableObj = data;
console.log(data);
});
<tbody ng-controller="studentController">
<tr ng-repeat="school in tableObj.Table track by school.SchoolId">
<td>{{school.SchoolId}}</td>
<td>{{school.schoolname}}</td>
<td>{{school.SCHOOLCODE}}</td>
<td>{{school.WEBSITE}}</td>
<td>{{school.USEREMAIL}}</td>
</tr>
</tbody>
From the Docs:
Best Practice: If you are working with objects that have a unique identifier property, you should track by this identifier instead of the object instance, e.g. item in items track by item.id. Should you reload your data later, ngRepeat will not have to rebuild the DOM elements for items it has already rendered, even if the JavaScript objects in the collection have been substituted for new ones. For large collections, this significantly improves rendering performance.
— AngularJS ng-repeat API Reference
Just replace your result with result.Table in your controller because if you properly see your response it is inside "Table" named array. Try this you should be able to see your records
SMSApp.controller('studentController', function ($scope, GetStudentService) {
$scope.msg = "Welcome from Controller";
GetStudentService.getAll().then(function (result) {
$scope.school = result.Table;
console.log(result);
});
});
Note: I have replaced your API call in the jsfiddle link with the response mentioned in the question.
JSFiddle Link : http://jsfiddle.net/zu8q7go6/9/
my problem is if I add new item to the database the ngTable don't updated with new data automatically but if I refresh the page (f5) the data is shown.
I use ng table to show data.
PS: the AngularJS consume data from JSON produced by restful WS from a JEE backend connected to a dataBase.
the ng-table :
<table ng-table="tablePy" show-filter="true"
class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th> Code </th>
<th> Libellé</th>
<th>Code Alphabetique 2</th>
<th>Code Alphabetique 3</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat=" py in paysValues | filter:searchValeur ">
<td align="right"> {{py.codPay}}</td>
<td > {{py.libPay}}</td>
<td> {{py.codAlph2}}</td>
<td> {{py.codAlph3}}</td>
</tr>
</tbody>
</table>
the function that fill the table is :
var initPaysData = function () {
var promise =
allPaysService.getPays();
promise.then(
function (res) {
$scope.paysValues = res.data;
$scope.tablePy = new NgTableParams({}, {dataset: $scope.paysValues});
},
function (error) {
$log.error('failure Pays charging', error);
})
};
initPaysData();
I use the factory to get All data from the WS:
BrokoApp.factory('allPaysService', function ($http) {
return {
getPays: function () {
return $http.get('http://localhost:8080/BrokWeb/webresources/referentiel/pays');
}
}
});
this code work but if I add new item to the table is don't shown
the code of add is:
$scope.addPays = function () {
$scope.selectedPy = $scope.libPay;
ngDialog.openConfirm({
template: 'modalDialogAdd',
className: 'ngdialog-theme-default',
scope: $scope
}).then(function () {
console.log('***** before add length=' + $scope.paysValues.length);
ajouterPays();
initPaysData();
console.log('***** after add length=' + $scope.paysValues.length);
$scope.tablePy.total($scope.paysValues.length);
$scope.tablePy.reload();
}, function () {
setNotification(notifications, 'danger', 'Erreur', 'Vous avez annule l operation');
});
};
the console.log show that the length of the List of data is the same before and after Add, the console show:
***** before add length=152
***** after add length=152
XHR finished loading: GET "http://localhost:8080/BrokWeb/webresources/referentiel/pays".
a XHR finished loading: POST "http://localhost:8080/BrokWeb/webresources/referentiel/pays".
the function AjouterPays is
var ajouterPays = function () {
var paysData = {
codAlph2: $scope.codAlph2,
// getting data from the adding form
};
var res = addPaysService.addPys(paysData);
res.success(function () {
setNotification(notifications, 'success', 'Succes', 'Ajout de ' + paysData.libPay);
});
res.error(function () {
setNotification(notifications, 'danger', 'Erreur', 'Erreur est servenue au cours de la creation');
});
// Making the fields empty
$scope.codAlph2 = '';
};
i use the factory addPaysService to post data
BrokoApp.factory('addPaysService', function ($http) {
return {
addPys: function (PyData) {
return $http.post('http://localhost:8080/BrokWeb/webresources/referentiel/pays', PyData);
}
}
});
Can anybody help me.
One simple approach for the updation of the data after you post/save any data or record to the database can be
just have a get request after the save/update is successful
i mean you can call the service/factory function which has the get request to the data base and then assign the response to the scope object of the table
Thank you
In case of the POST success, you can add the created element (if returned by your service) in $scope.paysValues.
Maybe something like that :
var ajouterPays = function () {
var paysData = {
codAlph2: $scope.codAlph2,
// getting data from the adding form
};
var promise = addPaysService.addPys(paysData);
promise.success(function ( response ) {
$scope.paysValues.push( response.data );
setNotification(notifications, 'success', 'Succes', 'Ajout de ' + paysData.libPay);
});
promise.error(function () {
setNotification(notifications, 'danger', 'Erreur', 'Erreur est servenue au cours de la creation');
});
// Making the fields empty
$scope.codAlph2 = '';
};
If your service does not return the created element in case of success, you can simple push the data you sent instead.
PS: note that success() and error() methods on an HttpPromise are deprecated from Angular 1.4.4 (see https://code.angularjs.org/1.4.4/docs/api/ng/service/$http).
I have a table on my layout page with a list of jobs. i am using rootscope and sessionStorage to keep what ever is selected active through out the site. Every job has changeOrders. When I highlight a job I then click on the changeOrder view. the changeOrders that belong to that job appear on a table. when I double click on one of them to open the modal nothing happens and I get the error message. However when I select a new Job on the jobs table it will then work. So it is that initial try that does not work.
Error Message
TypeError: Cannot read property 'JobName' of undefined
at Scope.$scope.editChangeOrderModal (http://localhost:44301/MyScripts/JobController.js:186:40)
at http://localhost:44301/Scripts/angular.js:10836:21
at http://localhost:44301/Scripts/angular.js:19094:17
at Scope.$eval (http://localhost:44301/Scripts/angular.js:12673:28)
at Scope.$apply (http://localhost:44301/Scripts/angular.js:12771:23)
at HTMLTableCellElement.<anonymous> (http://localhost:44301/Scripts/angular.js:19093:21)
at HTMLTableCellElement.x.event.dispatch (http://localhost:44301/Scripts/jquery-1.10.2.min.js:22:14129)
at HTMLTableCellElement.v.handle (http://localhost:44301/Scripts/jquery-1.10.2.min.js:22:10873)
Controller
//Edit ChangeOrder Modal
$scope.currentItem = null;
$scope.editChangeOrderModal = function (model) {
$scope.JobName = $rootScope.job.JobName;
$scope.JobId = $rootScope.job.JobId;
$scope.currentItem = model;
$ekathuwa.modal({
id: "editChangeOrderModal", contentStyle: "width:800px;heigth:400px",
scope: $scope,
templateURL: "ModalEditChangeOrder"
});
}`
//Sync Table Selections / sessionStorage
$scope.selectedJob = $sessionStorage.$default($scope.jobArray[1]);
$scope.selectJob = function (job) { $rootScope.job = job; angular.extend($scope.selectedJob, job); };
$scope.clearSelectedJob = function () { $sessionStorage.$reset(); };`
Layout page Main Job table
<table class=" table table-bordred table-striped table-hover">
<tr><th>No</th><th>Name</th></tr>
<tr ng-repeat="job in jobArray" class="pointer" ng-class="{highlight: job.JobNumber===selectedJob.JobNumber}">
<td ng-dblclick="editJobModal(job)" ng-click="selectJob(job)">{{job.JobNumber}}</td>
<td ng-dblclick="editJobModal(job)" ng-click="selectJob(job)">{{job.JobName}}</td>
</tr>
</table>
</div><!--End Job Tabl
Updated Code
//Edit ChangeOrder Modal
$scope.currentItem = null;
$scope.editChangeOrderModal = function (model) {
if ($rootScope.hasOwnProperty('job') && $rootScope.job != null) {
$scope.JobName = $rootScope.job.JobName;
$scope.JobId = $rootScope.job.JobId;
}
//$scope.JobName = $rootScope.job.JobName;
//$scope.JobId = $rootScope.job.JobId;
$scope.currentItem = model;
$ekathuwa.modal({
id: "editChangeOrderModal", contentStyle: "width:800px;heigth:400px",
scope: $scope,
templateURL: "ModalEditChangeOrder"
});
}
//GET Jobs
$scope.jobArray = {};
JobGet.query().then(function (data) { $scope.jobArray = data; }, function (reason) { errorMngrSvc.handleError(reason); });
Like typmeJV said, $rootScope.job is null.
You can do:
if ($rootScope.hasOwnProperty('job') && $rootScope.job != null) {
$scope.JobName = $rootScope.job.JobName;
$scope.JobId = $rootScope.job.JobId;
}
But this still smells bad? If the job object is missing from the $rootScope bad things may happen.
Why are you putting the job on the $rootScope?
I am trying to make ng-table work by example 6 (ajax data loading) but instead of using mock backend I use actual DreamFactory backend connected to MongoDB. My relevant code looks like this now:
MainApp.factory('Servant', function ($resource) {
"use strict";
console.log('loading');
return $resource('https://dsp-mydspname.cloud.dreamfactory.com:443/rest/mongodb/tablename/:id/?app_name=appname&fields=*', {}, { update: { method: 'PUT' }, query: {
method: 'GET',
isArray: false
} });
});
var MainCtrl = function ($scope, $timeout, $resource, Servant, ngTableParams) {
"use strict";
$scope.action="Add";
var Api = Servant;
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
}, {
total: 0, // length of data
getData: function($defer, params) {
// ajax request to api
Api.get(params.url(), function(data) {
$timeout(function() {
// update table params
params.total(data.record.length);
// set new data
$defer.resolve(data.record);
}, 500);
});
}
});
}
The table is displying data but it displays all data on one page, I cant figure out how to pass "count" and "offset" parameters into my api call. Any help would be appreciated.
Sorry for the delayed response. I played a little with ng-table and found that I was spending a lot of time trying to make it work and couldn't get it to. So..I thought it would be more helpful to show you how to build your own table with pagination so you can adapt it for any situation that may arise using DreamFactory. Here's the code. You should be able to copy and paste. Just make sure to add your table fields to the table row for data. The table headers will populate automatically.
Here is the controller and the service with comments:
.controller('TableCtrl', ['$scope', 'Servant', function($scope, Servant) {
// function to get records for building the table
var _getRecords = function(fieldsStr, limitInt, offsetInt, schemaBool) {
Servant.get({fields: fieldsStr, limit: limitInt, offset: offsetInt, include_schema: schemaBool},
function(data) {
$scope.table = data;
}
)
};
// Get the total records on load
Servant.get({fields: 'id'}, function(data) {
// Get the total number of records
$scope.totalRecords = data.record.length;
});
// Options for rest call
$scope.fields = '*';
$scope.currentOffset = 0;
$scope.limit = 4;
// Used to do pagination
// store total records
$scope.totalRecords = 0;
// store page objects
$scope.pageObjs = [];
// Get initial data
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
// Pagination
$scope.next = function() {
//check if we are on the last page
if ($scope.currentOffset == $scope.pageObjs[$scope.pageObjs.length - 1].pageOffset) {
return false;
}
// we are not
// advance the page
else {
$scope.currentOffset = $scope.currentOffset + $scope.limit;
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
}
};
// change page directly
$scope.changePage = function (offsetInt) {
$scope.currentOffset = offsetInt;
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
};
$scope.back = function() {
// are we on the first page
if ($scope.currentOffset == 0) {
return false
}
// we are not
// go previous page
else {
$scope.currentOffset = $scope.currentOffset - $scope.limit;
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
}
};
// watch for total records to be populated. When we have this number
// we can generate our page objects that will help build our pagination
$scope.$watch('totalRecords', function(newValue, oldValue) {
var numPages = Math.ceil(newValue / $scope.limit);
for(var i = 0; i < numPages; i++) {
$scope.pageObjs.push({pageNumber: i, pageOffset: i*$scope.limit})
}
});
}])
.service('Servant', ['$resource', function($resource) {
// define and return our $resource
// replace /rest/db/TheTable with your mongodb/tablename
// you don't need the port either
return $resource('http://localhost:8081/rest/db/TheTable',
{
// set params to bind too
app_name: APP_NAME
fields: '#fields',
limit: '#limit',
offset: '#offset'
},
{
// set update method to 'PUT'
update: {
method: 'PUT'
}
}
)
}]);
Here is the template i used:
<table class="table">
<!-- this will build the table headers dynamically -->
<!-- they will populate in order of the table's schema -->
<tr>
<th data-ng-repeat="field in table.meta.schema.field">
{{field.name}}
</th>
</tr>
<!-- replace these fields with your field names -->
<!-- for example: {{row.YOUR_FIELD_NAME}} -->
<tr data-ng-repeat="row in table.record">
<td>
{{row.id}}
</td>
<td>
{{row.first_name}}
</td>
<td>
{{row.last_name}}
</td>
</tr>
</table>
<!-- this will build dynamically as well-->
<ul class="pagination">
<li data-ng-click="back()"><a>«</a></li>
<li data-ng-click="changePage(page.pageOffset)" data-ng-repeat="page in pageObjs"><a>{{page.pageNumber + 1}}</a>
</li>
<li data-ng-click="next()"><a>»</a></li>
</ul>
I am displaying a list of elements inside a ng-include.
The list of elements comes from the server using $resource query service.
The list is paginated with the ui-bootstrap pagination directive. the server send the pagination informations inside the Json header (properties are named X-MyApp-…) and are intercepted by the query callback function.
here is the html :
<table ng-include src="'partials/tplList.html'" ng-init="listInit = {'type': collec.type, 'offset': 1}" ng-controller="ListCtrl" >
</table>
the tplList.html :
<tbody ng-init="loadList(listInit)"><tr ng-repeat="elm in list">
<td>{{elm.prop1}}</td><td>{{elm.prop2}}</td><td>{{elm.prop3}}</td>
</tr></tbody>
<tfoot><tr><td colspan="4">
<span ng-show="pageCount>1">
<pagination num-pages="pageCount" current-page="currentPage" max-size="10" on-select-page="loadList(collect(listInit, {offset: page}))">
</pagination>
</span>
</td></tr></tfoot>
and the controller:
controller('ListCtrl', ['$scope', 'List', function($scope, List) {
// collect: concatenate the objects before to send it to loadList()
$scope.collect = function (a,b){
var c = {};
for (var att in a) { c[att] = a[att]; }
for (var att in b) { c[att] = b[att]; }
return c;
}
$scope.loadList = function (param) {
$scope.list = List.query(p, function(list, response) {
$scope.currentPage = response("X-MyApp-currentPage");
$scope.pageCount = response("X-MyApp-pagesCount");
console.log($scope.currentPage); // returns 1 when the page loads.
});
}
}])
and the service :
factory('List', function($resource){
return $resource('url/to/the/json/:type', {type:'#type'});
})
everything is working fine except one thing : when the page loads, the first page button ("1") inside the pagination component is not disabled like it should (and the "previous" and "first" buttons are not either). It's not disabled until i click on another page number (which is disabled correctly when selected) and then click back on the first page button.
any idea ?
This happens because ng-include creates a new scope and the model is not modified in your $parent scope.
Try the following code or create a controller that communicates with the parent one.
<pagination num-pages="pageCount" current-page="$parent.currentPage" max-size="10" on-select-page="loadList(collect(listInit, {offset: page}))">
</pagination>
i found a way to make it work:
removed this line from the controller :
$scope.currentPage = response("X-MyApp-currentPage");
and added this one :
$scope.currentPage = 1;
which gives :
controller('ListCtrl', ['$scope', 'List', function($scope, List) {
// collect: concatenate the objects before to send it to loadList()
$scope.collect = function (a,b){
var c = {};
for (var att in a) { c[att] = a[att]; }
for (var att in b) { c[att] = b[att]; }
return c;
}
$scope.currentPage = 1;
$scope.loadList = function (param) {
$scope.list = List.query(p, function(list, response) {
$scope.pageCount = response("X-MyApp-pagesCount");
});
}
}])
apparently the pagination component doesn't need the X-MyApp-currentPage information from the server (and i'm not sure to understand why).