Is this a correct way of pagination in angularjs? - angularjs

On clicking "more" i call loadNextPage method that call loadComments method which load data based next id nextCommentId and push the data to allComments array and this array is rendered in html
$scope.loadNextPage = function()
{
loadComments($scope.nextCommentId);
}
function loadComments(page){
$scope.allComments.push(d.data);
..
..
$scope.nextCommentId = nextId;
}
Here is my html
<div ng-repeat="comment in allComments">
...
</div>
My question is, is this the correct way of doing pagination in angularjs as i am keeping all data in array so if data will grow it will consume memory.

<div data-pagination="" data-num-pages="numPages()"
data-current-page="currentPage" data-max-size="maxSize"
data-boundary-links="true"></div>
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);
});
});

Related

How to dynamically use object property as width in AngularJS (in ng-repeat)?

I cannot get the object's property to be read in ng-style(shape.radius || shape.length). I can't even get 1 to work at the moment, but would like to have an or statement included. Similar to my ng-class.
There is a button to generate shapes, and the shapes were created with a random size. Here is my code:
html:
<div ng-controller='ShapeController as sc'>
<div>
<p><input type="submit" value="Generate Random Shapes" ng-click="sc.generateShapes()"/></p>
<div ng-repeat="shape in sc.shapes">
<div class="shape" ng-class="{circle: shape.radius, square: shape.length}" ng-style="{'width': shape.length}"></div>
</div>
</div>
</div>
script:
var app = angular.module('app', []);
app.controller('ShapeController', function(){
var vm = this;
vm.shapes = [];
vm.randomShapes = [];
vm.width = 30;
function createCircle(radius) {
let circle = new Circle(radius);
vm.shapes.push(circle);
} // end createCircle
function createSquare(length) {
let square = new Square(length);
vm.shapes.push(square);
} // end createSquare
vm.generateShapes = function() {
let times = 50
for (let i = 0; i < times; i++) {
createCircle(getRandomNumber());
}
for (let i = 0; i < times; i++) {
createSquare(getRandomNumber());
}
sort(vm.shapes);
console.log(vm.shapes);
}; // end generateShapes
}); // end controller
function sort(arr) {
arr.sort(function(a,b){
return b.getArea() - a.getArea();
});
} // end sort function
function getRandomNumber() {
return Math.random() * (100-1) + 1;
}
width should be either in px(some unit like em, pt, etc) or %
ng-style="{'width': shape.length + 'px'}"

passing variable value from controller to view in AngularJS

I am developing an application where i popup a window and when it gets popup the next time i will try to open it should not be opened. Next time it should open When i will close the popup then it should open.
Now for that i am using count variable and whenever it will be 1 the popup opens and whenever it is greater than or equal to 2 it shows alert. But now when i close the popup it is not resetting the value of count to 0 in view.
In JSfiddle i tried using var self = this; it works fine but when i tried it on my code it says Uncaught Exception Typeerror cannot find property 'count' defined at line self.count = 0;
How to achieve this? or any alternate solution for this?
<a ui-sref-active="active" ng-click="count=count+1; connectMachine(machine, count)" ng-init="count=0" ><span><i class="fa fa-desktop fa-5x"></i></span></a>
$scope.connectMachine = function(machine, count) {
var promise = restAPIService.connectMachineService(
$scope.thisStudentThisBatch.guacProfileId,
machine.connectionId, $stateParams.batchID).get();
promise.$promise.then(function(response) {
var json = JSON.parse(response.data);
console.log(json.id);
var dnsUrl = $location.absUrl().split('/');
dnsUrl = dnsUrl[0] + '//' + dnsUrl[2];
var apiUrl = dnsUrl + $rootScope.apiUrl + "guacamole/disconnect/"
+ json.id;
var conn_params = $http.defaults.headers.common.Authorization
+ "++" + apiUrl;
$scope.machineURL = response.headers.url + "&conn_params="
+ conn_params;
var params = "height=" + screen.availHeight + ",width="
+ screen.availWidth;
var NewWin;
var self = this;
if ($scope.count == 1) {
NewWin = window.open($scope.machineURL);
} else if ($scope.count >= 2) {
alert("Back Off Back Off");
}
function checkWindow() {
if (NewWin && NewWin.closed) {
window.clearInterval(intervalID);
self.count = 0;
}
}
var intervalID = window.setInterval(checkWindow, 500);
}, function(error) {
dialogs.error("Error", error.data.error, {
'size' : 'sm'
});
});
}
You can use a variable defined on $scope to trigger the value of button instead of using ng-init
HTML:
<div ng-app="myApp">
<ul ng-controller="TodoCtrl">
<li class="list-group-item" ng-repeat="todo in todos">{{todo.text}}
<button class="btn btn-default" ng-click="addLike($index)">value- {{count[$index]}}</button>
</li>
</ul>
</div>
JS:
var myApp = angular.module('myApp', []);
function TodoCtrl($scope) {
$scope.todos = [{
text: 'todo one'
}, {
text: 'todo two',
done: false
}];
$scope.count = [0, 0];
$scope.addLike = function(index) {
var NewWin;
$scope.count[index] ++;
if ($scope.count[index] == 1) {
NewWin = window.open('https://www.google.com');
} else if ($scope.count >= 2) {
alert("Back Off Back Off");
}
function checkWindow() {
if (NewWin && NewWin.closed) {
window.clearInterval(intervalID);
$scope.count[index] = 0;
$scope.$apply();
}
}
var intervalID = window.setInterval(checkWindow, 500);
};
};
JS Fiddle :https://jsfiddle.net/p41dLjmn/

How do I slide the videos if I click on next button using angular.js

I able to embed the 4 videos in a particular div using "angular.js".But,I have so many videos nearly 20.
So,what I'm trying to do is,on click of "Next" button should get next 4 videos in a same div.How can I achieve this?
Can anyone please help me out regarding this issue ...
My html code:
<div class="panel-body">
<video width=176 height=99 style=" margin-left: 10px; margin-right: 10px;"
ng-repeat="videoSource in videoSources track by $index" autoplay
controls ng-src="{{videoSource | trustUrl}}">
</video>
<br> <a href="#" ng-click='loadVideos()'>Load videos</a>
<br><button type="button">Next</button>
</div>
My js code:
angular.module('Admin', [])
.controller('Home', function($scope) {
$scope.videoSources = [];
$scope.loadVideos = function() {
$scope.videoSources.push('http://54.88.118.248/Video/Digital_Hiring.mp4');
$scope.videoSources.push('http://54.88.118.248/Video/Customer_Service.mp4');
$scope.videoSources.push('http://54.88.118.248/Video/Digital_Hiring.mp4');
$scope.videoSources.push('http://54.88.118.248/Video/Digital_Hiring.mp4');
$scope.videoSources.push('http://54.88.118.248/Video/Customer_Service.mp4');
$scope.videoSources.push('http://54.88.118.248/Video/Digital_Hiring.mp4');
};
})
.filter("trustUrl", ['$sce',
function($sce) {
return function(recordingUrl) {
return $sce.trustAsResourceUrl(recordingUrl);
};
}
]);
The actual Angular way would be to create a custom filter to paginate the results. In the example, I've created a paginate filter that takes two parameters: pageNum and pageSize to slice the input array into the required chunk without any pre-processing of the array required.
Also added the necessary next and previous buttons and hid the load videos button.
angular.module('Admin', [])
.controller('Home', function($scope) {
$scope.pageNum = 0;
$scope.pageSize = 4;
$scope.isFirstPage = function() {
return $scope.pageNum === 0;
};
$scope.isLastPage = function() {
return $scope.pageNum >= Math.floor($scope.videoSources.length / $scope.pageSize);
};
$scope.prevPage = function() {
$scope.pageNum--;
};
$scope.nextPage = function() {
$scope.pageNum++;
};
$scope.videoSources = [];
$scope.loadVideos = function() {
for (var i = 0; i < 6; i++) {
$scope.videoSources.push('http://images.all-free-download.com/footage_preview/webm/boat_149.webm');
$scope.videoSources.push('http://images.all-free-download.com/footage_preview/webm/horse_riding_205.webm');
$scope.videoSources.push('http://images.all-free-download.com/footage_preview/webm/flower_124.webm');
}
};
})
.filter("trustUrl", ['$sce',
function($sce) {
return function(recordingUrl) {
return $sce.trustAsResourceUrl(recordingUrl);
};
}
])
.filter('paginate', function() {
console.log('creating paginate function', arguments);
return function(inputArray, pageNumber, pageSize) {
console.log('paginating', arguments);
pageNumber = pageNumber || 0;
pageSize = pageSize || 4;
if (!Array.isArray(inputArray)) return inputArray;
return inputArray.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div class="panel-body" ng-app="Admin" ng-controller="Home">
<video width=176 height=99 ng-repeat="videoSource in videoSources | paginate:pageNum:pageSize track by $index" autoplay controls ng-src="{{videoSource | trustUrl}}">
</video>
<div ng-show="videoSources.length">
<button ng-disabled="isFirstPage()" ng-click="prevPage()">Previous</button>
<button ng-disabled="isLastPage()" ng-click="nextPage()">Next</button>
</div>
<div ng-hide="videoSources.length">
<a href="#" ng-click='loadVideos()'>Load videos</a>
</div>
</div>
And because I felt like playing around with the code some more, here's a version that makes a pagination object, so that the functionality can be reused in different controllers and directives:
angular.module('Admin', [])
.controller('Home', function($scope, Pagination) {
$scope.videoSources = [];
$scope.pagination = new Pagination(4);
$scope.loadVideos = function() {
for (var i = 0; i < 6; i++) {
$scope.videoSources.push('http://images.all-free-download.com/footage_preview/webm/boat_149.webm');
$scope.videoSources.push('http://images.all-free-download.com/footage_preview/webm/horse_riding_205.webm');
$scope.videoSources.push('http://images.all-free-download.com/footage_preview/webm/flower_124.webm');
}
};
})
.factory('Pagination', function() {
var Pagination = function(pageSize) {
this.pageSize = pageSize || 4;
this.pageNum = 0;
this.sourceLength = 0;
};
Pagination.prototype.isFirstPage = function() {
return this.pageNum === 0;
};
Pagination.prototype.isLastPage = function(sourceLength) {
return this.pageNum >= Math.floor((sourceLength || this.sourceLength) / this.pageSize);
};
Pagination.prototype.prevPage = function() {
this.pageNum--;
};
Pagination.prototype.nextPage = function() {
this.pageNum++;
};
Pagination.prototype.setPage = function(pageNum) {
this.pageNum = pageNum;
};
Pagination.prototype.setPageSize = function(pageSize) {
this.pageSize = pageSize;
};
Pagination.prototype.setSourceLength = function(sourceLength) {
this.sourceLength = sourceLength;
}
Pagination.prototype.getPage = function() { return this.pageNum; };
Pagination.prototype.getPageSize = function() { return this.pageSize; };
Pagination.prototype.getSourceLength = function() { return this.sourceLength; };
return Pagination;
})
.filter("trustUrl", ['$sce',
function($sce) {
return function(recordingUrl) {
return $sce.trustAsResourceUrl(recordingUrl);
};
}
])
.filter('paginate', function() {
console.log('creating paginate function', arguments);
return function(inputArray, pageNumber, pageSize) {
console.log('paginating', arguments);
pageNumber = pageNumber || 0;
pageSize = pageSize || 4;
if (pageNumber && pageNumber.pageSize) pageSize = pageNumber.pageSize;
if (pageNumber && pageNumber.pageNum !== undefined) pageNumber = pageNumber.pageNum;
if (!Array.isArray(inputArray)) return inputArray;
return inputArray.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div class="panel-body" ng-app="Admin" ng-controller="Home">
<video width=176 height=99 ng-repeat="videoSource in videoSources | paginate:pagination track by $index" autoplay controls ng-src="{{videoSource | trustUrl}}">
</video>
<div ng-show="videoSources.length">
<button ng-disabled="pagination.isFirstPage()" ng-click="pagination.prevPage()">Previous</button>
<button ng-disabled="pagination.isLastPage(videoSources.length)" ng-click="pagination.nextPage()">Next</button>
</div>
<div ng-hide="videoSources.length">
<a href="#" ng-click='loadVideos()'>Load videos</a>
</div>
</div>
The filter now looks a bit stranger, because I wanted to keep the option to use it as paginate:pageNumber:pageSize but also allow it to be used as paginate:paginationObject and that took a little trickery. But now, our pagination functionality is abstracted away into a factory so it can be reused and keep our controller lean, and that is the Angular Way(TM) :D
Edit: Extra paginate filter explanation:
.filter('paginate', function() {
a console.log() call I used to debug that I forgot in here
console.log('creating paginate function', arguments);
To be able to accept parameters in an Angular filter, you have to return a function that needs those parameters from the filter function
return function(inputArray, pageNumber, pageSize) {
Another debugging console.log() call
console.log('paginating', arguments);
We can't be sure the parameters were passed in, so we provide sensible defaults (in this case, if pageNumber wasn't given, we'll set it to 0 and if pageSize wasn't given, we'll set it to 4)
pageNumber = pageNumber || 0;
pageSize = pageSize || 4;
Because we want to be able to pass in a Pagination object as a parameter instead of a page number & page size, we see if the first parameter isn't by chance an object containing pageSize and/or pageNum members, and if it is, we set the local pageNumber and pageSize variables to the values of the Pagination object's members
if (pageNumber && pageNumber.pageSize) pageSize = pageNumber.pageSize;
if (pageNumber && pageNumber.pageNum !== undefined) pageNumber = pageNumber.pageNum;
Then we check to see if the first parameter to the filter (the value being filtered) is actually an array. If it isn't, we just return the value unchanged. For example, if we were to have {{ 1 | paginate }} in an Angular template, the result would be 1, our algorithm wouldn't break. If it's an array, though, such as {{ [1, 2, 3, 4, 5] | paginate }} (with default paginate parameters) it would become [1, 2, 3, 4] and {{ [1, 2, 3, 4, 5] | paginate:0:2 }} would become [1, 2].
if (!Array.isArray(inputArray)) return inputArray;
And then the actual pagination logic (funny how it's way smaller than the input checking part of the code). We slice the input array to start at index pageNumber * pageSize and to end at index (pageNumber + 1) * pageSize (non-inclusive). Think of the first page (for pageSize = 4) having page number 0 and starting at index 0 and finishing at index 3 (so ending at index 4 (= 1 * 4) non-inclusive), page two having page number 1 and starting at index 4 (= 1 * 4) and finishing at index 7 (index 8 (= 2 * 4) non-inclusive, and so on. More information on Array.prototype.slice()
return inputArray.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
};
});
Without sliding effect, you can do it with pages:
Change loading videos:
$scope.videoSources.push({url:'video_here');
Then, page them:
var page = 1, perpage = 4;
$.each($scope.videoSources, function(k, v) {
v.page = (page++)/perpage;
Now that we have pages, in your HTML you can filter your data:
ng-repeat="video in videoSources | filter: {page: current_page}"
And next page ng-click:
ng-click="current_page++"
Same for previous page.
**Important noticing: because I changed your array to contain objects, to access the video you need to use video.url in your ng-src

Angular Pagination with Show All Records and Show Less Records

I am using AngularJS to show JSON data in table format. I have done with the fetching data. i have also implemented the pagination for the data movement.
Here I have three Link's to Adjust the Data like "Show All Records", "Show 10 More Records" and "Reset to 10 Records.
JavaScript:
var app = angular.module("MyApp",['ui.bootstrap']);
app.controller("MyController",function($scope,$http){
$http({method:"GET",url:'db.json'}).success(function(data,status,headers,config){
$scope.DBTotalData = data.length;
$scope.TotalPages='';
$scope.filteredapp = [],$scope.currentPage = 1,$scope.numPerPage = 5,$scope.maxSize = 1;
$scope.numPages = function () {
return Math.ceil(data.length / $scope.numPerPage);
};
$scope.$watch('currentPage + numPerPage', function() {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
, end = begin + $scope.numPerPage;
$scope.TotalPages=Math.ceil(parseInt(data.length,0)/parseInt($scope.numPerPage,0));
$scope.filteredapp = data.slice(begin, end);
$scope.DBData=$scope.filteredapp;
});
}).error(function(data,status,headers,config){
console.debug("error");
});
});
HTML:
<div data-pagination="" data-num-pages="numPages()" data-current-page="currentPage" data-max-size="maxSize" data-boundary-links="true"></div>
<div class="rgDataShowCtrl">
Show 10 More Records
Reset to 10 Records
Show All Results <div class="clear"></div></div>
<div class="clear"></div>
<tr ng-repeat="dData in DBData">
<td>{{dData.IaAcqNumber}}</td>
<td>{{dData.IaAssetNumber}}</td>
<td>{{dData.IaRepAssetNumber}}</td>
<td>{{dData.IaYearApp}}</td>
<td>{{dData.IaMake1}}</td>
<td>{{dData.IaModelRP}}</td>
<td>{{dData.IaOrganization}}</td>
<td>{{dData.IaDepartment}}</td>
<td>{{dData.IaTemplate}}</td>
</tr>
Javascript:
var app = angular.module("MyApp",['ui.bootstrap']);
app.controller("MyController",function($scope,$http){
$http({method:"GET",url:'db.json'}).success(function(data,status,headers,config){
$scope.DBTotalData = data.length;
$scope.TotalPages='';
$scope.filteredapp = [],$scope.currentPage = 1,$scope.numPerPage = 10,$scope.maxSize = 1;
$scope.ShowAll=function(value){
if(value==0){
$scope.numPerPage = $scope.numPerPage+10;
$(".showreset").show();
}else if(value==1){
$scope.numPerPage = 10;
$(".showreset").hide();
}else if(value==2){
$scope.numPerPage = data.length;
$(".showreset").show();
}
};
$scope.numPages = function () {
return Math.ceil(data.length / $scope.numPerPage);
};
$scope.$watch('currentPage + numPerPage', function() {
var begin = (($scope.currentPage - 1) * $scope.numPerPage)
, end = begin + $scope.numPerPage;
$scope.TotalPages=Math.ceil(parseInt(data.length,0)/parseInt($scope.numPerPage,0));
$scope.filteredapp = data.slice(begin, end);
$scope.DBData=$scope.filteredapp;
});
}).error(function(data,status,headers,config){
console.debug("error");
});
});
HTML:
<div data-pagination="" data-num-pages="numPages()" data-current-page="currentPage" data-max-size="maxSize" data-boundary-links="true"></div>
<div class="rgDataShowCtrl">
Show More per Page
Reset to 10 per Page
Show All Results
<div class="clear"></div>
</div>
<div class="clear"></div>
<tr ng-repeat="dData in DBData">
<td>{{dData.IaAcqNumber}}</td>
<td>{{dData.IaAssetNumber}}</td>
<td>{{dData.IaRepAssetNumber}}</td>
<td>{{dData.IaYearApp}}</td>
<td>{{dData.IaMake1}}</td>
<td>{{dData.IaModelRP}}</td>
<td>{{dData.IaOrganization}}</td>
<td>{{dData.IaDepartment}}</td>
<td>{{dData.IaTemplate}}</td>
</tr>

how to wrap text in angularjs and save the position

I would like to wrap text with span tag and save the position.
I know how to do it with JS but i dont know how to do it with angularjs
Here is what i have done:
http://jsfiddle.net/ymeaL06j/1/
This function gives me the position of the text in the DIV
function getSelectionPosition() {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(document.getElementById("code"));
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
};
I take the start and end positions and insert them as an attribute in the span tag
After this i would like to save all the marked positions and load it later, i have a function that select text and then i can wrap it (i hope that there is a better solution)
function setSelection(savedSel) {
var charIndex = 0, range = document.createRange();
range.setStart(document.getElementById("code"), 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
You can use the same code that you illustrated above and put it inside of your angularjs controller.
Refer to my plunker code; it is a simple angularjs version of your jsfiddle code.
For example, suppose that a snippet of the index.html looks like this:
<body ng-controller="MainCtrl">
<div id="code">This is <b>some text</b> bla bla bla</div>
<br />
<input type="button" value="Mark!" ng-click="markText()" />
<input type="button" value="Remove marks!" ng-click="removeMarks()" />
</body>
Then the example angularjs controller, MainCtrl, could look like this:
app.controller('MainCtrl', function($scope) {
var getSelectionPosition = function () {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(document.getElementById("code"));
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
}
$scope.markText = function() {
var currPosition = getSelectionPosition();
var selection = window.getSelection().getRangeAt(0);
var selectedText = selection.extractContents();
var span = document.createElement("span");
span.className = "Mark";
span.setAttribute("PosStart", currPosition.start);
span.setAttribute("PosEnd", currPosition.end);
span.appendChild(selectedText);
selection.insertNode(span);
};
$scope.removeMarks = function() {
$(".Mark").each(function () {
$(this).contents().unwrap();
});
};
});
Notice that the MainCtrl is the angularjs controller for the body. The ng-click on the buttons reference the markText and removeMarks functions in the controller's scope. The logic in the functions are exactly the same as you referenced in your question (and jsfiddle).
None of your JS code changed other than moving the functions inside of the controller. Again, check out the plunker above to see the actual code working.

Resources