I have a pagination factory, which I didn't write, i'm just using, it gets passed the $scope and a string, the string representing the http action.
It works with GET requests however I am now trying to implement it on a POST request and for some reason it is not working. The pagination bar is loaded, with the right amount of buttons. e.g I have 1 thousand records it loads 100 buttons 10 records per page but when clicking the buttons the data is static, it doesn't update.
Pagination factory:
angular.module('customers')
.factory('PaginationFactory', PaginationFactory);
function PaginationFactory($scope, action) {
$scope.filteredPages = [];
$scope.currentPage = 1;
$scope.numPerPage = 10;
$scope.maxSize = 15;
$scope.makePages = function () {
$scope.search_customers = [];
angular.forEach($scope.get_list, function (item) {
//Push the items into the list...
if (callerAction == 'search_customers') {
$scope.search_customers.push(item);
}
});
};
$scope.$watch('currentPage + numPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
end = begin + $scope.numPerPage;
if (callerAction == 'search_customers') {
var pages = $scope.filteredPages = $scope.search_customers.slice(begin, end);
return pages;
});
$scope.makePages();
}
HTML:
<ul uib-pagination
total-items="search_customers.length"
ng-model="currentPage"
max-size="maxSize"
boundary-link-numbers="true"
rotate="false">
</ul>
Post request:
$scope.searchCustomers = function() {
$scope.status = $scope.selected.charAt(0);
$http.post(API_URL+"v1/customers/search", $scope.searchData)
.then(function (response){
var action = 'search_customers';
$scope.get_list = response.data;
console.log($scope)
new PaginationFactory($scope, action);
}, function (response) {
console.log("no data");
});
If anybody could help would be appreciated. Thank you.
Related
Need to keep track of my offset so that I can get the next set each time either scroll or click 'Load more'. It improves performance. I am trying out here by setting offset and limit and passing as request params to my node server,but how to update or increment after that limit using offset:
my url as: /foo?limit=7&&offset=0;
My angular controller function as:
$scope.findDetails = function(){
var limit = 10;
var offset = 0;
//DataService.getUsers(limit,offset).then(function(customerdetails){
DataService.getUsers({limit,offset},function(customerdetails){
$scope.customers = customerdetails;
}, function(error){
$scope.status = 'Unable to load customer data: ' + error.message;
});
};
You must keep the offset in the scope of the controller and update the offset every time the infinite directive request more records to display:
$scope.limit = 10;
$scope.offset = 0;
//bind this function to the ng-infinite directive
$scope.infiniteScrollFunction = function() {
$scope.offset += $scope.limit;
$scope.findDetails();
};
$scope.findDetails = function() {
DataService.getUsers({limit: $scope.limit,offset: $scope.offset},
function(customerdetails){
...
}
var $scope.height = $('#div-height').height()
var flag = false;
var $scope.customers = []
$(window).scroll(function() {
if ($(this).scrollTop() > $scope.height-2000) {
if (!flag) {
flag = true;
refreshCustomers();
}
}
});
function refreshCustomers() {
DataService.getCustomers().then(function (data) {
$scope.customers = $scope.customers.concat(data);
setTimeout(function () {
$scope.height = $('#div-height').height();
flag = false
}, 0.1);
});
}
In DataService
factory.getCustomers = function(){
return $http.get(...api......&&limit=7).then(function (results) {
var customers = results.data.customers;
return customers;
});
};
Now after the window is scrolled up to certain height(windowHeight-2000px), the api is called again to get data. The previous data is being concatenated with present data.
Angular loads new pages just by moving the scroll bar. Not when it reaches the bottom. It even loads new posts when i scroll up.
app.factory('Recipes', function ($http) {
var Recipes = function () {
this.recipes = [];
this.loading = false;
this.page = 1;
};
Recipes.prototype.nextPage = function () {
var url = 'api/recipes?page=' + this.page;
if (this.loading) return;
this.loading = true;
$http.get(url)
.success(function (data) {
console.log(this.page);
for (var i = 0; i < data.data.length; i++) {
this.recipes.push(data.data[i]);
}
this.page++;
this.loading = false;
}.bind(this));
};
return Recipes;
});
app.controller('RecipesCtrl', function ($scope, $http, Recipes) {
$scope.recipes = new Recipes();
});
This is the angular part. This is the laravel part:
Route::group(['prefix' => 'api'], function () {
Route::get('recipes', [
'as' => 'recipe.all',
'uses' => 'RecipeController#recipes'
]);});
And this is the html part:
<div ng-controller="RecipesCtrl">
<div class="recipe row" infinite-scroll="recipes.nextPage()" infinite-scroll-distance="1"
infinite-scroll-disabled='recipes.loading'>
<div ng-repeat="recipe in recipes.recipes | orderBy:sortOrder:sortReverse | limitTo:myLimit">
...
</div>
</div>
</div>
First Problem: Why does infinite-scroll load more content constantly?
infinite-scroll-distance is set to 1 in your code. This means that when the element is within 1000 pixels of the browsers bottom the directive will fetch more data.
If you change this to a value closer to 0, the user will have to scroll further for the trigger to get activated.
Second Problem: How do I prevent the directive from loading more content, when there is no more content to return?
One solution to stopping the directive from continuously loading more data is by setting the recipes.loading = true; when the returned data is empty.
As such:
.success(function (data) {
console.log(this.page);
for (var i = 0; i < data.data.length; i++) {
this.recipes.push(data.data[i]);
}
this.page++;
this.loading = false;
recipes.loading = true; // This should prevent more code from being loaded.
}
I made AngularJS pagination with spring mvc It works well ,but the application get a large amount of data from database so the application is very slow when I get first page because it get all records,Can anyone help me to solve this problem?I want to get subset of data from database depending on angularJS pagination
Spring mvc Controlller
#RequestMapping(value = "/rest/contacts",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<Contact> getAll() {
return contactRepository.findAll();
}
AngularJS Service
pagingpocApp.factory('Contact', function ($resource) {
return $resource('app/rest/contacts/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': { method: 'GET'}
});
});
AngularJS Controller
pagingpocApp.controller('ContactController', function ($scope, $filter,resolvedContact, Contact, resolvedRole) {
$scope.contacts = resolvedContact;
var sortingOrder = 'firstName';
$scope.sortingOrder = sortingOrder;
$scope.reverse = false;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 10;
$scope.pagedItems = [];
$scope.currentPage = 0;
var searchMatch = function (haystack, needle) {
if (!needle) {
return true;
}
return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1;
};
// init the filtered items
$scope.search = function () {
$scope.filteredItems = $filter('filter')($scope.contacts, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
if ($scope.sortingOrder !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
// calculate page in place
$scope.groupToPages = function () {
$scope.pagedItems = [];
for (var i = 0; i < $scope.filteredItems.length; i++) {
if (i % $scope.itemsPerPage === 0) {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)] = [ $scope.filteredItems[i] ];
} else {
$scope.pagedItems[Math.floor(i / $scope.itemsPerPage)].push($scope.filteredItems[i]);
}
}
};
$scope.range = function (start, end) {
var ret = [];
if (!end) {
end = start;
start = 0;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
return ret;
};
$scope.prevPage = function () {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.nextPage = function () {
if ($scope.currentPage < $scope.pagedItems.length - 1) {
$scope.currentPage++;
}
};
$scope.setPage = function () {
$scope.currentPage = this.n;
};
// functions have been describe process the data for display
$scope.search();
// change sorting order
$scope.sort_by = function(newSortingOrder) {
if ($scope.sortingOrder == newSortingOrder)
$scope.reverse = !$scope.reverse;
$scope.sortingOrder = newSortingOrder;
// icon setup
$('th i').each(function(){
// icon reset
$(this).removeClass().addClass('icon-sort');
});
if ($scope.reverse)
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-up');
else
$('th.'+new_sorting_order+' i').removeClass().addClass('icon-chevron-down');
};
});
One quick option would be to create a get method on your API that only returns a subset of the data, maybe only 25 contacts at a time, or a page or two worth of data. Then you could create a service in angular that makes that get call every 3 seconds or so to get the next 25 contacts. A sort of lazy loading technique.
Ben Nadel does a great job in this article of outlining how his company handles large sets of images being loaded to a page using a lazy loading technique. Reading through his example could give you a nice starting point.
Edit: I'm also going to recommend you refer to this solution for an answer slightly more on point to what you're looking to achieve. He recommends pushing data to your controller as soon as it's found:
function MyCtrl($scope, $timeout, $q) {
var fetchOne = function() {
var deferred = $q.defer();
$timeout(function() {
deferred.resolve([random(), random() + 100, random() + 200]);
}, random() * 5000);
return deferred.promise;
};
$scope.scans = [];
for (var i = 0; i < 2; i++) {
fetchOne().then(function(items) {
angular.forEach(items, function(item) {
$scope.scans.push(item);
});
});
};
}
I'm modifying the way an app gets it's data.
The app originally got data on the page load like this
<script>
var entries = <?php echo $this->entriesData; ?>;
</script>
and then in the angular controller
$scope.entries = entries;
Requirements changed so that a user would be able to go forward or backward one week so I added a factory to the app that is supposed to load the data when the page loads and then refresh the data when changeweek() is fired. According to the console the factory (loadData) fires when the page loads and then again on changeweek() and data comes down from the server as expected. The problem is that the view doesn't display the data. I'm assuming that I'm not returning the data to the $scope.entries correctly. Help please!
var timeEntry = angular.module('timeEntry', ['ui.select2']);
timeEntry.factory('loadData', function($http){
var url = 'index/getentries';
var returnData = '';
var factory = {};
factory.getData = function(sDate, eDate){
$.post(url, {week_start: sDate, week_end: eDate})
.done(function(json, textStatus){
if (textStatus === 'success') {
returnData = json;
}else{
// handle fail
}
})
.fail(function(){})
.always(function(){});
return returnData;
};
return factory;
});
timeEntry.controller('timeEntryController', ['$scope','loadData', function ($scope, loadData) {
$scope.loading = true;
$scope.date = [];
$scope.date.start = startDate;
$scope.date.end = endDate;
$scope.entries = loadData.getData($scope.date.start, $scope.date.end);
$scope.weekTotal = 0;
$scope.timeEntryError = [];
$scope.$watch('entries', function(newNames, oldNames) {
$scope.dataCount = newNames.length;
$scope.timeEntryError = [];
calculateTotals();
checkDayHours();
checkSpecialDays();
}, true);
$scope.changeWeek = function(change) {
sdate = moment($scope.date.start);
edate = moment($scope.date.end);
$scope.date.start = sdate.add(moment.duration(change, 'week')).format('YYYY-MM-DD');
$scope.date.end = edate.add(moment.duration(change, 'week')).format('YYYY-MM-DD');
$scope.entries = loadData.getData();
};
}]);
I'm attempting to implement pagination on a angular/bootstrap site. I have the data showing with the correct # of per-page rows, I have the angular paging showing the right number of pages...but heck if I can find anywhere that tells me HOW to use the paging to refresh my data when a page # is clicked...?! {{currentPage}} is updating, but not sure how to have it call getPresentations to update the list.
<div>
{{noOfPages}} {{currentPage}} {{maxSize}}
<pagination num-pages="noOfPages" current-page="currentPage"></pagination>
</div>
<script type="text/javascript">
angular.module('app', ['ui', 'shared', 'ui.bootstrap']).controller('AppCtl', function ($scope, $http, $window) {
var mvc = $window.MVC;
$scope.noOfPages = 0;
$scope.currentPage = 1;
$scope.maxSize = 5;
$scope.getPresentations = function () {
$http.get(mvc.base + "API/Presentations?page=" + $scope.currentPage + "&itemsPerPage=10")
.success(function (result) {
$scope.presentations = result.Items;
$scope.noOfPages = result.TotalPages;
$scope.currentPage = result.Page;
})
.error(function (result, status) {
$scope.newModal.errors = mvc.getApiErrors(status, result);
});
};
$scope.getPresentations();
});
</script>
You've got 2 options:
$watch the current-page property
use the onSelectPage callback
Here is the relevant page with $watch
$scope.$watch('currentPage', function(newPage){
$scope.watchPage = newPage;
//or any other code here
});
And here one using the callback:
$scope.pageChanged = function(page) {
$scope.callbackPage = page;
$scope.watchPage = newPage;
};
used like:
<pagination on-select-page="pageChanged(page)" num-pages="noOfPages" current-page="currentPage"></pagination>
And finally the working plunk showing the 2 approaches:
http://plnkr.co/edit/UgOQo7?p=preview
#pkozlowski.opensource answer is correct, except recent versions of bootstrap have changed on-select-page to ng-change.