I am trying to implement a simple pagination with directives in angularjs
Controller
//load the result server
$scope.getData = function(page) {
$http.post('/search?page='+page,searchParams).then(function (response) {
if(response.data.status){
$scope.arts = response.data.result;
$scope.currentPage = response.data.currentPage;
$scope.pageCount = response.data.pageCount;
}else{
$scope.arts = [];
}
},function (err) {
$scope.arts = [];
console.log(err);
});
}
When the HTTP call is finished i am using a directive is to print the pagination links.
HTML
<ul class="pagination pagination-circle pg-blue mb-0 paginate">
<pagination pagecount="pageCount" currentpage="currentPage"></pagination>
</ul>
Directive
This directive just build pagination links and returns to
app.directive('pagination',function () {
//custom directive for build pagination
return {
restrict: 'E',
scope: {
pagecount: '=',
currentpage: '='
},
link:function (scope,elem,attr) {
var element = angular.element(document.getElementsByClassName('paginate'));
var str ='';
var i = 1;
if (scope.currentpage > 5) {
i = +scope.currentpage - 4;
}
for (i; i<=scope.pagecount; i++) {
if (scope.currentpage == i) {
str+='<li class="page-item active"><a href="#" class="page-link" >'+i+'</a></li>'
}else{
str+=' <li class="page-item"><a class="page-link" href="" ng-click="getData('+i+')">'+i+'</a></li>'
}
if (i == (+scope.currentpage + 4)) {
break;
}
}
element.prepend(str);
}
};
})
But the problem is ng-click="getData()" in the anchor is not worked why its not getting worked.
the difference is getData() is defined in controller
I think href="" might be redirecting or refreshing your page, which is why ng-click is not getting triggered.
Try it as below.
href="#"
or
href="javascript:void(0)"
You need to pass that function to directive for access that function from directive.
Html
<ul class="pagination pagination-circle pg-blue mb-0 paginate">
<pagination pagecount="pageCount" get-data="getData()" currentpage="currentPage"></pagination>
</ul>
Directive
This directive just build pagination links and returns to
app.directive('pagination',function () {
//custom directive for build pagination
return {
restrict: 'E',
scope: {
pagecount: '=',
currentpage: '=',
getData: '&' /**This is how you can access function of controller**/
},
link:function (scope,elem,attr) {
var element = angular.element(document.getElementsByClassName('paginate'));
var str ='';
var i = 1;
if (scope.currentpage > 5) {
i = +scope.currentpage - 4;
}
for (i; i<=scope.pagecount; i++) {
if (scope.currentpage == i) {
str+='<li class="page-item active"><a href="#" class="page-link" >'+i+'</a></li>'
}else{
str+=' <li class="page-item"><a class="page-link" href="" ng-click="getData('+i+')">'+i+'</a></li>'
}
if (i == (+scope.currentpage + 4)) {
break;
}
}
element.prepend(str);
}
};
})
Related
I am making a small Contacts application with Bootstrap 4 and AngularJS v1.6.6.
The application simply displays an Users JSON. Since the JSON returns a large number of users, the application also has a pagination feature.
The pagination worked fine as part of the app's controller, but since I tried to turn it into a service, it does not work anymore.
See a functional version of the application, with the pagination inside the controller HERE.
The application controller:
// Create an Angular module named "contactsApp"
var app = angular.module("contactsApp", []);
// Create controller for the "contactsApp" module
app.controller("contactsCtrl", ["$scope", "$http", "$filter", "paginationService", function($scope, $http, $filter) {
var url = "https://randomuser.me/api/?&results=100&inc=name,location,email,cell,picture";
$scope.contactList = [];
$scope.search = "";
$scope.filterList = function() {
var oldList = $scope.contactList || [];
$scope.contactList = $filter('filter')($scope.contacts, $scope.search);
if (oldList.length != $scope.contactList.length) {
$scope.pageNum = 1;
$scope.startAt = 0;
};
$scope.itemsCount = $scope.contactList.length;
$scope.pageMax = Math.ceil($scope.itemsCount / $scope.perPage);
};
$http.get(url)
.then(function(data) {
// contacts arary
$scope.contacts = data.data.results;
$scope.filterList();
// Pagination Service
$scope.paginateContacts = function(){
$scope.pagination = paginationService.paginateContacts();
}
});
}]);
The service:
app.factory('paginationService', function(){
return {
paginateContacts: function(){
// Paginate
$scope.pageNum = 1;
$scope.perPage = 24;
$scope.startAt = 0;
$scope.filterList();
$scope.currentPage = function(index) {
$scope.pageNum = index + 1;
$scope.startAt = index * $scope.perPage;
};
$scope.prevPage = function() {
if ($scope.pageNum > 1) {
$scope.pageNum = $scope.pageNum - 1;
$scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
}
};
$scope.nextPage = function() {
if ($scope.pageNum < $scope.pageMax) {
$scope.pageNum = $scope.pageNum + 1;
$scope.startAt = ($scope.pageNum - 1) * $scope.perPage;
}
};
}
}
});
In the view:
<div ng-if="pageMax > 1">
<ul class="pagination pagination-sm justify-content-center">
<li class="page-item"><i class="fa fa-chevron-left"></i></li>
<li ng-repeat="n in [].constructor(pageMax) track by $index" ng-class="{true: 'active'}[$index == pageNum - 1]">
{{$index+1}}
</li>
<li><i class="fa fa-chevron-right"></i></li>
</ul>
</div>
The service file is included in the project (correctly, in my opinion) after the app.js file:
<script src="js/app.js"></script>
<script src="js/paginationService.js"></script>
I am not an advanced AngularJS user so I don't know: what is missing?
It appears that the service needs to be defined before the controller, otherwise it cannot be injected properly.
So you could either move the paginationService into app.js:
var app = angular.module("contactsApp", []);
app.factory('paginationService', function(){
//...
});
app.controller("contactsCtrl", ["$scope", "$http", "$filter", "paginationService", function($scope, $http, $filter) {
//...
});
Or else move the controller out to a separate file that is included after the paginationServices.js file.
Take a look at this plunker. Try modifying line 6 - remove character 5, i.e. the space that separates the star and slash that would close the multi-line comment.
var app2 = angular.module("webApp2", [])
.controller("webCtrl2", function ($scope, $window, $state, $http) {
console.log("hi " + $state.params.usermail);
$scope.uName = $state.params.usermail;
$scope.useriden = $state.params.user;
console.log("hbdhakkdjf" + " " + $scope.uName)
//$scope.data = $window.sessionStorage.getItem("Mydata");
//console.log("data "+$scope.data);
var usersList = [];
var frndsAdded = [];
$http.get("http://192.168.2.3:3000/userslist")
.then(function (response) {
usersList = response.data;
//$scope.friendsList = response.data;
//.................................................................
$http.get("http://192.168.2.3:3000/sendfriendrequests/" + $scope.uName)
.then(function (response) {
frndsAdded = response.data;
},
function (response) {
console.log("error");
});
// console.log("array print" + JSON.stringify($scope.usersList));
}, function (response) {
console.log("response");
});
console.log(frndsAdded);
console.log("print userid" + $scope.useriden);
$scope.addFrnd = function (frnd, index) {
var data = {
"userId": $scope.useriden,
"requestname": frnd,
"username": $scope.uName
};
console.log(data);
var req = {
method: 'POST',
url: 'http://192.168.2.3:3000/friendrequests',
data: data
}
$http(req).then(function (response) {
console.log("hjhuhjh" + JSON.stringify(response.data));
$scope.usersList.splice("index");
}, function (response) {
console.log(JSON.stringify(response));
});
}
$scope.logoutFn = function () {
$state.go("signup");
}
});
<nav class="navbar navbar-default well well-sm">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">WebChat</a>
</div>
<ul class="nav navbar-nav pull-right">
<li>Home</li>
<li style = margin-top:5%>
<div class = "dropdown">
<a href="#" data-toggle="dropdown">
<i class="glyphicon glyphicon-user"></i>Add Friends<span class = "caret"></span>
</a>
<ul class = "dropdown-menu list-group" style = " overflow: scroll">
<!--<li class = "list-group-item" ng-repeat = "seeFrnd in usersList track by $index" ng-bind = "seeFrnd.username">name
<button class = "btn btn-primary" ng-click = "addFrnd()">Add Friend</button>
</li>-->
<li class = "list-group-item" ng-repeat = "seeFrnd in usersList track by $index"><span ng-bind="seeFrnd.username"></span>
<button class = "btn btn-primary btn-sm" ng-click = "addFrnd(seeFrnd.username,$index)" class = "buttn" style="float: right">Add Friend</button>
</li>
</ul>
</div>
</li>
<li>
</li>
<li>Logout</li>
</ul>
</div>
</nav>
<div ui-view></div>
I am doing chat application here I am getting two arrays.one is for users list and other is for friends list.both arrays are in different functions.I need to compare that both arrays.how could i do that?
angular.forEach(arr1, function(value1, key1) {
angular.forEach(arr2, function(value2, key2) {
//Comparison logic
});
});
Define the two arrays on $scope. You have to use your logic to compare two arrays inside the second API call after getting the second array values. If you want to do it outside then you have to wait for the asychronous API call to finish, so that you will get the complete array.
$scope.usersList = [];
$sccope.frndsAdded = [];
$http.get("http://192.168.2.3:3000/userslist").then(function(response) {
$scope.usersList = response.data;
//$scope.friendsList = response.data;
//.................................................................
$http.get("http://192.168.2.3:3000/sendfriendrequests/" + $scope.uName).then(function(response) {
$scope.frndsAdded = response.data;
//Comaprison Logic
for (var i = 0; i < $scope.usersList.length; i++) {
for (var j = 0; j < $scope.frndsAdded.length; j++) {
if ($scope.usersList[i].request == $scope.frndsAdded[j].request)
//ur logic
}
}
}, function(response) {
console.log("error");
});
// console.log("array print" + JSON.stringify($scope.usersList));
}, function(response) {
console.log("response");
});
Now with my code i see all pages, but i want to limit the number of links.
If i have 10 pages, but i want to see only five:
1 2 3 4 5,
5 6 7 8 9.
How can i do that? This is plunk demo on part of my code
This is my controller:
var booksController = function () {
function all(context) {
var size = 2,
page = +context.params['page'] || 0;
templates.get('books')
.then(function (template) {
var booksRef = firebase.database().ref('books');
booksRef = booksRef.orderByChild('timestamp');
booksRef.on('value', function (snapshot) {
this.data = [];
snapshot.forEach(function (child) {
this.data.push(child.val());
}.bind(this));
var pagesLen = Math.ceil(data.length / size),
pages = [];
for (var i = 0; i < pagesLen; i+= 1) {
pages.push({
page: i,
displayPage: i + 1
});
}
data = data.slice(page * size, (page + 1) * size);
context.$element().html(template({
books: data,
pages: pages
}));
});
});
}
return { all: all };
}();
And my hadlebars template:
<section id="primary-content">
<div class="wrapper">
<h1 class="above">Books: </h1>
{{#each books}}
<h1>{{title}}</h1>
{{/each}}
<div id="medium">
</div> {{!--end medium--}}
<ul class="pagination">
{{#pages}}
<li>
<a class="btn btn-sm btn-default" href="#/books/{{page}}">{{displayPage}}</a>
</li>
{{/pages}}
</ul>
</div>
I'm trying to learn local storage. I have five links each with a data-date attribute and I want them to be sorted using that attribute. I've tried numerous ways but nothing seems to work. From what I understand, I should parse before sorting but it didn't work for me. I must have done it wrong because I don't see how else to do it.
Here is my HTML:
<div id="div1">
<input id='clearHistory' type='button' value='Remove All History' />
<input id='showHistory' type='button' value='Show History' />
<ul id='history'>
<li>
<a class='date' href="#aa" data-date="November 12, 2001 03:24:00">Link 1</a>
</li>
<li>
<a class='date' href="#bb" data-date="August 4, 1993 03:24:00">Link 2</a>
</li>
<li>
<a class='date' href="#cc" data-date="October 17, 1995 03:24:00">Link 3</a>
</li>
<li>
<a class='date' href="#dd" data-date="December 1, 2010 03:24:00">Link 4</a>
</li>
<li>
<a class='date' href="#ee" data-date="August 17, 2004 03:24:00">Link 5</a>
</li>
</ul>
</div>
<p>Click on 'Show History' to see the 'user history'.</p>
<ul id='storedHistory'></ul>
And my JavaScript:
$(document).ready(function() {
var storedHistory = document.getElementById('storedHistory');
Storage.prototype.setObject = function(key, value) {
this.setItem(key, JSON.stringify(value));
};
Storage.prototype.getObject = function(key) {
var value = this.getItem(key);
return value && JSON.parse(value);
};
//function sortDatesAscending(a, b) { return a.valueOf() - b.valueOf(); } function sortDatesDescending(a, b) { return b.valueOf() - a.valueOf(); }
function sortLinkDatesAscending(obj1, obj2) {
return obj1.date.valueOf() - obj2.date.valueOf();
}
function sortLinkDatesDescending(obj1, obj2) {
return obj2.date.valueOf() - obj1.date.valueOf();
}
var history = {
items: []
};
// Get each anchor and retrieve its date and link. Add to an object and add that object to the history's array Sort by ascending. Add to local storage.
$('ul > li > a').click(function(e) {
var date = $(this).attr('data-date');
var listData = {
link: $(this).attr("href"),
date: date
};
history.items.push(listData);
window.localStorage.setObject("history", history);
});
/* Remove items from local storage */
$('#clearHistory').click(function() {
window.localStorage.clear();
});
/* Retrieve items from local storage and add to stored history unordered list */
$('#showHistory').click(function() {
console.log(window.localStorage);
var listHistory = localStorage.getObject('history');
var counter = 1;
for (var i = 0; i < listHistory.items.length; i++) {
$("#storedHistory").append('<li>' + counter + '. Link: ' + listHistory.items[i].link + '<br>' + 'Date: ' + listHistory.items[i].date + '</li>');
counter++;
}
});
});
And here is the jsfiddle: https://jsfiddle.net/fLLsfd5j/2/
Try this for sorting! (http://trentrichardson.com/2013/12/16/sort-dom-elements-jquery/)
var $history = $('#history li'),
$historyA = $history.children();
$historyA.sort(function (a, b) {
var an = Date.parse(a.getAttribute('data-date')).valueOf(),
bn = Date.parse(b.getAttribute('data-date')).valueOf();
if (an > bn) {
return 1;
}
if (an < bn) {
return -1;
}
return 0;
});
$('#history').empty();
$.each($historyA, function () {
$('#history').append($('<li>').html(this));
});
I guess this should do your job
function getHistory(){
var as = document.querySelectorAll(".date"); // get elements with date class
Array.prototype.map.call(as, e => e.cloneNode(true)) //clone them into an array and sort
.sort((p,c) => Date.parse(p.dataset.date)<=Date.parse(c.dataset.date) ? -1 : 1)
.forEach((e,i) => as[i].parentNode.replaceChild(e, as[i]));
}
showHistory.onclick = getHistory; //add "click" eL to the DOM element with showHistory id
http://jsbin.com/yoraqusora/2/edit?js,console,output
I am new to angular and I have been trying to make a pretty advanced directive.
Most of the directive works, but there are two issues presenting themselves currently and I think they are both related to the scope.
Here is my directive:
angular.module('test')
.directive('testKitDesigner', function () {
panels = [];
function bindEvents() {
console.log("bindingEvents");
var styledElements = ["piping", "panel-1", "panel-2", "panel-3", "panel-4", "panel-5", "panel-6", "panel-7", "panel-8", "panel-9", "panel-10"];
for (var i = 0; i < styledElements.length; i++) {
var target = document.getElementById(styledElements[i]);
console.log(target);
if (target) {
bindEvent(target);
}
}
};
function bindEvent(target) {
console.log(target);
target.bindEvent("ngClick", selectPanel);
};
function selectPanel(event) {
var path = angular.element(event.target);
panels = []; // Reset
if (attrs.testKitDesigner && attrs.testKitDesigner === 'advanced') {
panels.push(path);
} else {
var parent = path.parent();
var paths = parent.children();
for (var i = 0; i < paths.length; i++) {
var current = angular.element(paths[i]);
var tag = current[0].nodeName;
if (tag === 'path' || tag === 'polyline') {
panels.push(current);
}
}
console.log(panels.length);
}
};
return {
restrict: 'A',
templateUrl: 'Views/Templates/designer.html',
link: function (scope, element, attrs) {
scope.step = 0;
scope.sport = 'General';
scope.garment = 'Dress';
scope.design = 'Angelus';
scope.nextStep = function () {
scope.step++;
};
scope.setSport = function (sport) {
scope.sport = sport;
scope.setSvg();
scope.nextStep();
};
scope.setGarment = function (garment) {
scope.garment = garment;
scope.setSvg();
scope.nextStep();
};
scope.setDesign = function (design) {
scope.design = design;
scope.setSvg();
scope.nextStep();
};
scope.setSvg = function () {
var children = element.children();
var template = scope.sport + '/' + scope.garment + '/' + scope.design;
for (var i = 0; i < children.length; i++) {
var child = angular.element(children[0]);
if (child.hasClass('base')) {
child.attr('test-svg', template);
bindEvents();
return;
}
}
}
scope.setColor = function (color) {
for (var i = 0; i < panels.length; i++) {
var panel = angular.element(panels[i]);
var parent = panel.parent();
if (parent.attr('id') === 'piping') {
panel.css({
'stroke': color
});
} else {
panel.css({
'fill': color
});
}
}
};
scope.init = function () {
bindEvents();
};
scope.init(); // Set our defaults;
}
}
})
.directive('testSvg', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.contentUrl = 'Views/Templates/' + attrs.testSvg + '.svg';
attrs.$observe('testSvg', function () {
console.log(attrs.testSvg);
scope.contentUrl = 'Views/Templates/' + attrs.testSvg + '.svg';
});
},
template: '<div ng-include="contentUrl"></div>'
};
});
And the designer template looks like this:
<div class="base" test-svg="/General/Polo/Angelus">
</div>
<div class="options">
<h1>Simple kit designer</h1>
<div ng-hide="step != 0">
<p>Choose your sport.</p>
<ul class="list-unstyled">
<li><a href ng-click="setSport('Netball');">Netball</a></li>
<li><a href ng-click="setSport('General');">General</a></li>
</ul>
</div>
<div ng-hide="step != 1">
<p>Choose your garment.</p>
<ul class="list-unstyled">
<li><a href ng-click="setGarment('Dress');">Dress</a></li>
<li><a href ng-click="setGarment('Polo');">Polo</a></li>
</ul>
</div>
<div ng-hide="step != 2">
<p>Choose your design.</p>
<ul class="list-unstyled">
<li><a href ng-click="setDesign('Angelus');">Angelus</a></li>
</ul>
</div>
<div class="colors" ng-hide="step != 3">
<p>Click an area to change the colour.</p>
<ul id="colour-picker" ng-hide="!picking" class="colours">
<li><a class="colour-red" href ng-click="setColor('red');"></a></li>
<li><a class="colour-orange" href ng-click="setColor('orange');"></a></li>
<li><a class="colour-yellow" href ng-click="setColor('yellow');"></a></li>
<li><a class="colour-green" href ng-click="setColor('green');"></a></li>
<li><a class="colour-blue" href ng-click="setColor('blue');"></a></li>
<li><a class="colour-indigo" href ng-click="setColor('indigo');"></a></li>
<li><a class="colour-violet" href ng-click="setColor('violet');"></a></li>
</ul>
</div>
</div>
Now, what should happen, is that when the user selects a sport or garment or design, the test-svg attribute should change to the new values and then the relevant svg will be loaded.
The attribute does change, but the observe function never gets called. I am certain that this is something to do with the scope but I can't figure it out.
You are adding test-svg attribute during link phase of test-kit-designer. The test-svg attribute are not compiled as directive so the $observe is not triggered, read up on $compile to solve your problem.
However, I would recommend restructuring your code. Consider using test-svg in the template, exposing template from setSvg in test-kit-designer and two-way binding it to another variable in test-svg.