ng-repeat not updating properly in Angular js - javascript

I'm trying to put pagination with ng-repeat. Getting result but by the time showing old data and suddenly hide and show new set data, like jerking. My angularjs version is "1.5.8".
$scope.gap = 5;
$scope.filteredItems = [];
$scope.groupedItems = [];
$scope.itemsPerPage = 5;
$scope.pagedItems = [];
$scope.currentPage = 0;
var resultData = [...];
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')(resultData, function (item) {
for(var attr in item) {
if (searchMatch(item[attr], $scope.query))
return true;
}
return false;
});
// take care of the sorting order
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
$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]);
}
}
console.log($scope.pagedItems)
};
$scope.range = function (size,start, end) {
var ret = [];
//console.log(size,start, end);
if (size < end) {
end = size;
start = size-$scope.gap;
}
for (var i = start; i < end; i++) {
ret.push(i);
}
// console.log(ret);
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 () {
console.log($scope.pagedItems[$scope.currentPage]);
$scope.currentPage = this.n;
};
$scope.search();
html
<tr ng-repeat="user in pagedItems[currentPage]" >
<td>{{user.name}} {{$index}}</td>
</tr>
As above code, that table row update as 5 row. but when I click next or page numbers showing 10 rows and hide 5 rows. I hope you understand guys! Help me.

In my opinion you are thinking wrong, it's simpler to use custom filter and break up your business logic like this
app.filter('startFrom', function() {
return function(input, start) {
start = +start;
return input.slice(start);
}
});
then in the controller you can do
$scope.showResults = function() {
$scope.list = $filter('startFrom')($scope.initialList, $scope.page * $scope.itemsPerPage);
$scope.list = $filter('limitTo')($scope.list, $scope.itemsPerPage);
}
};
now you need only to update $scope.page and reuse $scope.showResults() to update the view
<tr ng-repeat="user in list" >
<td>{{user.name}} {{$index}}</td>
</tr>

I don't think that your problem is cause by ng-repeat. I just take your code, add some dummy data and do a test and it's totally work fine.
You can check it here https://codepen.io/Cushdrive/pen/zvPPXd
Because angular is two way binding, so I'm wonder that could it be some paging info was triggered somewhere. Could you double check on some variable like currentPage itemPerPages or pagedItems to see if it being used somewhere else?

Related

Can't display JSON-objects from session-storage in AngularJS

I'm having problem displaying a JSON-object named "currentSet" from session-storage. When I instead use a JSON-file from a folder everything works fine, which means the HTML-code is probably fine. I have narrowed the problem down to either the $scope.set or the loadQuiz-function and have tried several things, but can't get it to work. This is the relevant parts from the controller:
$scope.set = angular.fromJson(sessionStorage.getItem('currentSet')); //doesn't work
//$scope.set = 'data/konflikter.js'; //works
$scope.defaultConfig = {
'autoMove': true,
'pageSize': 1,
'showPager': false
}
$scope.onSelect = function (question, choice) {
question.choices.forEach(function (element, index, array) {
question.Answered = choice;
});
if ($scope.defaultConfig.autoMove == true && $scope.currentPage < $scope.totalItems) {
$scope.currentPage++;
}
else {
$scope.onSubmit();
}
}
$scope.onSubmit = function () {
var answers = [];
$scope.questions.forEach(function (question, index) {
answers.push({'questionid': question._id, 'answer': question.Answered});
});
$http.post('https://fhsclassroom.mybluemix.net/api/quiz/submit', answers).success(function (data, status) {
$location.path('/');
});
}
$scope.pageCount = function () {
return Math.ceil($scope.questions.length / $scope.itemsPerPage);
};
$scope.loadQuiz = function (data) {
$http.get(data)
.then(function (res) {
$scope.name = res.data.name;
$scope.questions = res.data.questions;
$scope.totalItems = $scope.questions.length;
$scope.itemsPerPage = $scope.defaultConfig.pageSize;
$scope.currentPage = 1;
$scope.$watch('currentPage + itemsPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredQuestions = $scope.questions.slice(begin, end);
});
});
}
$scope.loadQuiz($scope.set);
Ok I figured out what's wrong, you are loading file so you need to get file - or import it to get the contents that's why it works with your:
$scope.set = 'data/konflikter.js'; //works but combined with http request
If you wish to pass data from dataStorage you will need to change your loadQuiz not to have http request like this:
$scope.loadQuiz = function (res) {
$scope.name = res.data.name;
$scope.questions = res.data.questions;
$scope.totalItems = $scope.questions.length;
$scope.itemsPerPage = $scope.defaultConfig.pageSize;
$scope.currentPage = 1;
$scope.$watch('currentPage + itemsPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredQuestions = $scope.questions.slice(begin, end);
});
}
With the help of #pegla I was able to solve the problem like this:
$scope.loadQuiz = function () {
$scope.set = angular.fromJson(sessionStorage.getItem('currentSet'));
$scope.questionsetid = $scope.set.questions[0].questionsetid;
$scope.name = $scope.set.name;
$scope.questions = $scope.set.questions;
$scope.totalItems = $scope.set.questions.length;
$scope.itemsPerPage = $scope.defaultConfig.pageSize;
$scope.currentPage = 1;
$scope.$watch('currentPage + itemsPerPage', function () {
var begin = (($scope.currentPage - 1) * $scope.itemsPerPage),
end = begin + $scope.itemsPerPage;
$scope.filteredQuestions = $scope.questions.slice(begin, end);
});
}
$scope.loadQuiz();

Angular 1 button instead of 3

I have a problem with this pagination code. I have 1 button instead of 3. Can you help?
paginator.js
$scope.generateButtons = function () {
var buttons = [],
pageCount = getPageCount(),
buttonCount;
console.log("page " + pageCount);
buttonCount = pageCount > 2 ? 3 : pageCount;
for (var i = 0; i < buttonCount; i++) {
var index = +$scope.offset + i -1;
if (index > 0) {
buttons.push(index);
}
};
return buttons;
};
View in plunker
My suggestion is to use Angular UI bootstrap pagination, and not write it from scratch https://angular-ui.github.io/bootstrap/#/pagination
angular.module('ui.bootstrap.demo').controller('PaginationDemoCtrl', function ($scope, $log) {
$scope.totalItems = 64;
$scope.currentPage = 4;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
$log.log('Page changed to: ' + $scope.currentPage);
};
$scope.maxSize = 5;
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;
});
It's really not about angular related problem. Its all about the logic for $scope.generateButtons = function () {...} Please change your logic as you need. Here is your code (edited) for displaying 3 buttons.
$scope.generateButtons = function () {
var buttons = [],
pageCount = getPageCount(),
buttonCount;
buttonCount = pageCount > 2 ? 3 : pageCount;
for (var i = 0; i < buttonCount; i++) {
var index = parseInt($scope.offset) + i+1;
if (index >= 0) { // this `if` is not really needed
buttons.push(index);
}
};
return buttons;
};
Enjoy!

Pagination in Angular.js

I am trying to add pagination in Angular js.Sinch my server returns huge number of rows on each query So i am using some limit offset to get only 101 rows(required rows+1) at a time.(Building array of 20 pages ,reusing extra row value for next request.)
No- of rows per page=5
So on getting 101 rows means i can paginate upto 20 pages. Since i already have an extra row So i know there is more data left , So on next page request again am querying to get rows 101-201. But my doubt here is how to add logic in next page and previous page function and how to build next or previous set of data?
My app.js-
My 1st time request-
$scope.startingid = null;
$scope.numberofrows= 101;
Api.customer.query({ productId : $scope.customer , productperiod :$scope.customerPeriod,startingid:$scope.startingid,numberofrows:$scope.numberofrows }).$promise.then(function(result) {
if(result){
if(result&&result.length==0){
$scope.addErrorAlert("No Customer data found with this productId and Period.", true);
$scope.displayPage = 'search';
return;
}
$scope.customerResult = result;
$scope.displayPage = 'drill';
$scope.showData();
}
// Pagination Logic-
My code is working fine if result set is small number of data. But need to implement in such a way that it can handle large number of rows as well.
few doubts-
1. how to build the data for request 101-201.
2. next and previous page logic
$scope.paged = function (valLists,itemsPerPage)
{
var retVal = [];
for (var i = 0; i < valLists.length; i++) {
if (i % itemsPerPage === 0) {
retVal[Math.floor(i / itemsPerPage)] = [valLists[i]];
} else {
retVal[Math.floor(i / itemsPerPage)].push(valLists[i]);
}
}
return retVal;
};
$scope.pagination = function () {
$scope.ItemsByPage = $scope.paged( $scope.customerResult, $scope.itemsPerPage );
};
$scope.showData = function( ){
// $scope.noOfrows = 101;
$scope.itemsPerPage = 5;
$scope.currentPage = 0;
$scope.pagination();
$scope.range = function() {
var rangeSize = 4;
var ps = [];
var start;
start = $scope.currentPage;
if ( start > $scope.pageCount()-rangeSize ) {
start = $scope.pageCount()-rangeSize+1;
}
for (var i=start; i<start+rangeSize; i++) {
ps.push(i);
}
return ps;
};
$scope.prevPage = function() {
if ($scope.currentPage > 0) {
$scope.currentPage--;
}
};
$scope.DisablePrevPage = function() {
return $scope.currentPage === 0 ? "disabled" : "";
//?? TODO add logic for samething as disabled next page and build table data
};
$scope.pageCount = function() {
return Math.ceil($scope.customerResult.length/$scope.itemsPerPage)-1;
};
$scope.nextPage = function() {
if ($scope.currentPage < $scope.pageCount()) {
$scope.currentPage++;
}
};
$scope.DisableNextPage = function() {
if($scope.currentPage === $scope.pageCount()){
if($scope.noOfrows >$scope.customerResult.length)
return $scope.currentPage === $scope.pageCount() ? "disabled" : "";
$scope.noOfrows = $scope.noOfrows+ 100;
Api.customerReq.query({ productId : $scope.customerProduct , productperiod :$scope.customerPeriod, noOfrows:$scope.noOfrows }).$promise.then(function(result) {
if(result){
if(result&&result.length==0){
return $scope.currentPage === $scope.pageCount() ? "disabled" : "";
}
$scope.showData();// how to build all data on when i query for 101-201 data?
}
});
}
};
$scope.setPage = function(n) {
$scope.currentPage = n;
};
};

Recursive function to traverse grid goes crazy

When the user clicks on one of the blocks in the table ( see screenshot ) I want to find all neighbouring blocks with the same color. I am trying to do this recursively, but if I try it with more than three blocks it sometimes goes crazy and calls itself over and over until the program crashes.
As far as I can see, the objects are added to the array, but somehow my tests fails and the same object is added over and over and over.
Any insight on what the problem might be and how to solve it would be much appriciated!
Here's a screenshot
This is the function that is called when the user clicks on a block:
var $matchArray;
$('.block').click(function () {
$matchArray = [$(this)];
var $colorClass;
if ($(this).hasClass('red')) {
$colorClass = 'red';
} else if ($(this).hasClass('green')) {
$colorClass = 'green';
} else if ($(this).hasClass('blue')) {
$colorClass = 'blue';
} else {
$colorClass = 'error';
}
findAllSameColorNeighbours($(this), $colorClass);
});
And this is the recursive method:
findAllSameColorNeighbours = function ($this, $colorClass) {
$this.css('border-style', 'solid');
//LEFT
var $leftBlock = isLeftBlockSameColor($this, $colorClass);
if ($leftBlock != null) {
if (!(arrayContains($matchArray, $leftBlock))) {
$matchArray.push($leftBlock);
findAllSameColorNeighbours($leftBlock, $colorClass);
}
}
//ABOVE
//same as for LEFT
//RIGHT
//same as for LEFT
//BELOW
//same as for LEFT
}
This is how I find the neighboring cells, as far as I can see these work just fine. I have one for each direction:
isLeftBlockSameColor = function ($block, $color) {
var $this = $block;
var $tr = $this.parent().parent();
var col = $tr.children().index($this.parent().prev());
var $leftBlock = $this.parent().siblings().eq(col).children();
var $blockClassMatch = $leftBlock.hasClass($color);
if ($blockClassMatch) {
return $leftBlock;
}
else {
return null;
}
};
Here are some help methods to find out if the object is already in the array or not. I use the index of the row and cell to create a sort of latitude and longditude thing.
arrayContains = function ($array, $object) {
for (i = 0; i < Array.length; i++) {
if (compareIndex($array[i], $object)) {
say('true');
return true;
}
};
return false;
};
compareIndex = function ($obj1, $obj2) {
if ((getRowIndex($obj1)) === (getRowIndex($obj2)) {
if ((getCellIndex($obj1)) === (getCellIndex($obj2)) {
return true;
} else {
return false;
}
} else {
return false;
}
};
getCellIndex = function ($this) {
var $tr = $this.parent().parent();
var index = $tr.children().index($this.parent());
return index;
};
getRowIndex = function ($this) {
var $tr = $this.parent().parent();
var index = $tr.index();
return index;
};
There is a bug in the arrayContains function. The loop will iterates only once, because Array.length is equals to 1(As I tested with chrome browser, but I don't know why). You should use $array.length instead.
arrayContains = function ($array, $object) {
//for (i = 0; i < Array.length; i++) {
for (i = 0; i < $array.length; i++) {
if (compareIndex($array[i], $object)) {
say('true');
return true;
}
};
return false;
};

Angularjs splice in loop

I am building this angularjs app, its my first one. So huge learning curve. I cant seem to to delete items as well as my search doesn't work. I managed to get column sorting and pagination to work though.
I get no errors so i am not sure why the search and deleting of item row in table isnt working.
I have tried using this:
$scope.remove = function(client){
for(var i = $scope.clients.length - 1; i >= 0; i--){
if($scope.clients[i].name == client.name){
$scope.clients.splice(i,1);
}
}
}
Working example: http://plnkr.co/edit/f2ozbP4JxrRSvRGJAmQi
ANSWER, WORKING:
Thanks #DTing
$scope.remove = function(client){
$scope.filteredItems = $scope.filteredItems.filter(function(item) {
return item.name !== client.name;
});
$scope.groupToPages();
}
This should be your remove function:
$scope.remove = function(client){
for(var i = $scope.pagedItems[$scope.currentPage].length - 1; i >= 0; i--){
if($scope.pagedItems[$scope.currentPage][i].name == client.name){
$scope.pagedItems[$scope.currentPage].splice(i,1);
break;
}
}
}
This should be your search function (note creation of $scope.clientsCopy):
$scope.clientsCopy = angular.copy(data);
$scope.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.clientsCopy, function (item) {
for(var attr in item) {
if ($scope.searchMatch(item.name, $scope.query))
return true;
}
return false;
}
);
// take care of the sorting order
if ($scope.sortField !== '') {
$scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortField, $scope.reverse);
}
$scope.currentPage = 0;
// now group by pages
$scope.groupToPages();
};
Plunker
You are trying to alter your $scope.clients which actually is empty because in your groupToPages function you set it to an empty array and repopulate or use it.
$scope.groupToPages = function () {
$scope.clients = [];
You can get it to work by removing items from your filteredItems array.
$scope.remove = function(client){
$scope.filteredItems.splice($scope.filteredItems.indexOf(client),1);
$scope.groupToPages();
}
http://plnkr.co/edit/z9NxW2FgYDlgLB20daO9?p=preview

Categories