How can i apply pagination to display 3 items per page - javascript

I have an list of items fetched as below:
<ul id="products" class="abcd" style="display: block;">
<li class="productslist">item1</li>
<li class="productslist">item2</li>
<li class="productslist">item3</li>
<li class="productslist">item4</li>
<li class="productslist">item5</li>
<li class="productslist">item6</li>
<li class="productslist">item7</li>
<li class="productslist">item8</li>
<li class="productslist">item9</li>
<li class="productslist">item10</li>
<li class="productslist">item11</li>
<li class="productslist">item12</li>
<li class="productslist">item13</li>
</ul>
Now I need to display 3 items per page after applying pagination. Kindly help me with Javascript.

This question is quite broad, however considering that this solution is not a great solution for longer lists, the code below will help you understand what to do.
const list = [...document.querySelectorAll('.productslist')];
let count = 0;
const items_per_page = 3;
const pagination_numbers_container = document.querySelector('.pagination-numbers');
const paginate = (p) => {
hideAll();
if(p === 'next') count += items_per_page;
else if(p === 'previous') count -= items_per_page;
else count = p;
if(count < 0 ) count = 0;
else if(count >= (list.length - items_per_page)) count = (list.length - items_per_page) + ((list.length+1) % items_per_page);
for(let i = count; i < (count+items_per_page); i++) {
if(list[i]) list[i].style.display = 'block';
}
}
const paginateNumberClickHandler = (evt) => {
const page = parseInt(evt.currentTarget.getAttribute('data-page'));
paginate(page * items_per_page)
}
const createPaginationNumbers = () => {
const total_pages_rest = list.length % items_per_page;
const total_pages = (list.length / items_per_page);
const pagination_numbers = [];
pagination_numbers_container.innerHTML = '';
for(let i = 0; i < total_pages; i++) {
pagination_numbers_container.innerHTML += `<button data-page="${i}" class="pag">${i+1}</button>`;
}
[...document.querySelectorAll('.pag')].forEach( (p) => p.addEventListener('click', paginateNumberClickHandler ));
}
const hideAll = () => list.forEach( (l) => l.style.display = 'none');
const next = document.querySelector('.next');
const previous = document.querySelector('.previous');
next.addEventListener('click', (e) => paginate("next"));
previous.addEventListener('click', (e) => paginate("previous"));
paginate(0);
createPaginationNumbers();
<ul id="products" class="abcd" style="display: block;">
<li class="productslist">item1</li>
<li class="productslist">item2</li>
<li class="productslist">item3</li>
<li class="productslist">item4</li>
<li class="productslist">item5</li>
<li class="productslist">item6</li>
<li class="productslist">item7</li>
<li class="productslist">item8</li>
<li class="productslist">item9</li>
<li class="productslist">item10</li>
<li class="productslist">item11</li>
<li class="productslist">item12</li>
<li class="productslist">item13</li>
</ul>
<div class="pagination-numbers">
</div>
<button class="previous">
Previous
</button>
<button class="next">
Next
</button>

Related

Javascript Nav with dropdown click event issue

I have a doropdown menu that should work when used/in view.
I would like to have a function that works only when the dropdown is used.
So Ideally navigation with dropdown and nav without.
the following fuctions will be added if dropdown exists.
The Click event doesn't seems to fire at all.
My assumption is that
const navLinks = dropDownBlock[i].querySelectorAll(".nav-items > li");
is't correct! or is not fired
I wan't to use as much as possible es6, and I wan't to make sure everything is reusable and works only when in view.
Demo here:
const dropDownBlock = document.querySelectorAll(".has-nav-panel");
let result = true;
for (let i = 0; i < dropDownBlock.length; i++) {
if (dropDownBlock[i] <= 0) {
result = false;
break;
}
const navLinks = dropDownBlock[i].querySelectorAll(".nav-items > li");
const dropdownCta = dropDownBlock[i].querySelector(".nav-panel-cta");
const dropdownPanel = dropDownBlock[i].querySelector(".nav-panel");
//-------------------------------------
//Doesn it have dropdown
//-------------------------------------
Array.prototype.forEach.call(navLinks, function (el, i) {
let currentNavLink = navLinks[i];
currentNavLink.addEventListener("click", function () {
console.log('click');
megaNavClickAndTouchHandler(navLinks, currentNavLink);
});
megaNavResetOnBreakPoint(navLinks, currentNavLink, mediaQuery);
});
function megaNavResetOnBreakPoint(elements, currentElement, mqNav) {
if (matchMedia) {
let navigationBar = currentElement.closest(".header");
let navigationItems = currentElement.closest(".nav-wrap");
mqNav.addListener(function () {
if (mqNav.matches) {
document.querySelectorAll("body")[0].classList.remove("is-no-scroll");
navigationBar.classList.remove("is-active");
navigationItems.classList.remove("is-active");
//navigationBar.querySelectorAll(".burger")[0].classList.remove("is-active");
megaNavClosePanels(elements);
} else {
megaNavClosePanels(elements);
}
});
}
}
function megaNavClickAndTouchHandler(elements, currentElement) {
let isSubNavLink = currentElement.classList.contains("has-nav-panel");
let isSubNavLinkActive = currentElement.classList.contains("is-active");
let navBarContainer = currentElement.closest(".header");
if (!isSubNavLink) {
window.location = currentElement.firstElementChild.getAttribute("href");
} else if (isSubNavLink && !isSubNavLinkActive) {
megaNavClosePanels(elements);
currentElement.classList.add("is-active");
dropdownCta.setAttribute("aria-expanded", true);
dropdownPanel.ariaHidden = "false";
} else {
megaNavClosePanels(elements);
}
}
function megaNavClosePanels(elements) {
for (let j = 0; j < elements.length; j++) {
if (elements[j].classList.contains("has-nav-panel")) {
elements[j].classList.remove("is-active");
dropdownCta.setAttribute("aria-expanded", false);
dropdownPanel.ariaHidden = "true";
}
}
}
//-------------------------------------
// end dropdown functions
//-------------------------------------
}
<header role="banner" class="header">
<div class="container-fluid g-0 bg-black">
<nav id="main-navigation" class="navigation">
<div class="container has-px-0 has-px-md-4">
<div class="nav-wrap" aria-label="main navigation">
<ul class="nav-items list-unstyled">
<li class="is-d-lg-flex active"><a class="nav-link" href="#">nav item</a></li>
<li class="is-d-lg-flex "><a class="nav-link" href="#">nav item</a></li>
<li class="is-d-lg-flex"><a class="nav-link" href="#">nav item</a></li>
<li class="has-nav-panel is-d-lg-flex is-align-center">
<button role="button" aria-expanded="false" class="nav-panel-cta has-pb-3 has-pt-3 has-px-4 has-p-lg-0"><span class="has-mr-2">Dropdown</span></button>
<div class="nav-panel" aria-hidden="true">
<div class="row no-gutters">
<div class="col-md-12">
<ul class="list-unstyled has-pl-3 has-pl-lg-0">
<li>nav item</li>
<li>nav item</li>
</ul>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</nav>
</div>
</header>
your html structure
<ul class="nav-items list-unstyled">
<li class="has-nav-panel is-d-lg-flex is-align-center">
but your script select the child then the parent
const dropDownBlock = document.querySelectorAll(".has-nav-panel");
.....
const navLinks = dropDownBlock[i].querySelectorAll(".nav-items > li");
I think you don't need to loop and here fix, replace
const dropDownBlock = document.querySelectorAll(".has-nav-panel");
let result = true;
for (let i = 0; i < dropDownBlock.length; i++) {
if (dropDownBlock[i] <= 0) {
result = false;
break;
}
const navLinks = dropDownBlock[i].querySelectorAll(".nav-items > li");
const dropdownCta = dropDownBlock[i].querySelector(".nav-panel-cta");
const dropdownPanel = dropDownBlock[i].querySelector(".nav-panel");
with
let result = true;
dropDown();
function dropDown() {
let dropDownBlock = document.querySelectorAll(".nav-items")
const navLinks = dropDownBlock[0].querySelectorAll(".has-nav-panel");
if (navLinks .length <= 0) {
result = false;
return;
}
const dropdownCta = dropDownBlock[0].querySelector(".nav-panel-cta");
const dropdownPanel = dropDownBlock[0].querySelector(".nav-panel");

Traversing the DOM, getting text with highest appearance and add a class to the parent

I am traversing this DOM:
<ul>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
<li class="item">
<span class="category">
some text
</span>
</li>
<li class="item">
<span class="category">
some text
</span>
</li>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
</ul>
With the following code:
var myNodelist = Array.from(document.querySelectorAll(".category"));
var obj = {};
for(var i = 0; i < myNodelist.length; i++){
//convert array to object with unique elements and number of times
each element is repeated
var x = myNodelist[i].innerHTML;
//console.log(x);
if(!obj[x]){
obj[x] = 1;
} else {
obj[x]++;
}
}
var index = 0;
var max = 0;
for(var obIndex in obj) {
// Traverse the object to get the element
if(obj[obIndex] > max) {
max = obj[obIndex];
index = obIndex.replace(" ", "");
}
}
console.log(index + " is max time repeated: " + max + " times." );
var v = document.getElementsByClassName("category");
for(var m = 0; m < myNodelist.length; m++) {
var subText = myNodelist[m].childNodes;
var len = subText.length;
for (var jj = 0; jj < len; jj++) {
if(subText[jj].nodeType === Node.TEXT_NODE) {
console.log(subText[jj].nodeValue);
subText[jj].nodeValue =
subText[jj].nodeValue.replace(/Mock/,"123");
}
}
}
Currently i am getting the index successfully with the value from the exertion of the highest text appearance in the DOM. Then i am looping through the Nodelist again, evaluating if its a,
Node.TEXT_NODE
https://developer.mozilla.org/de/docs/Web/API/Node/nodeType
Now i only know how to replace the
textNode.value
with another value.
What i am really trying to achieve is to get the parentNode of the textNode and add a class to it. If the condition for index (highest appearance) is met. What i found is
Adding a class to a given element. and
ParentNode MDN
The problem is i can't really figure out how to
access the parentNode out of the second for loop and add a class to
the parentNode, so all parents (span tags) that only have the index (text
value) get a certain class.
Thanks for help !
You can access to li using parentNode on the myNodelist[m]
var myNodelist = Array.from(document.querySelectorAll(".category"));
var obj = {};
for(var i = 0; i < myNodelist.length; i++){
//convert array to object with unique elements and number of times
//each element is repeated
var x = myNodelist[i].innerHTML;
//console.log(x);
if(!obj[x]){
obj[x] = 1;
} else {
obj[x]++;
}
}
var index = 0;
var max = 0;
for(var obIndex in obj) {
// Traverse the object to get the element
if(obj[obIndex] > max) {
max = obj[obIndex];
index = obIndex.replace(" ", "");
}
}
console.log(index + " is max time repeated: " + max + " times." );
var v = document.getElementsByClassName("category");
for(var m = 0; m < myNodelist.length; m++) {
var subText = myNodelist[m].childNodes;
var len = subText.length;
for (var jj = 0; jj < len; jj++) {
if(subText[jj].nodeType === Node.TEXT_NODE) {
if (obj[subText[jj].nodeValue] == max) {
myNodelist[m].parentNode.className += " red";
}
console.log(subText[jj].nodeValue);
subText[jj].nodeValue =
subText[jj].nodeValue.replace(/Mock/,"123");
}
}
}
.red {
color: red;
}
<ul>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
<li class="item">
<span class="category">
some text
</span>
</li>
<li class="item">
<span class="category">
some text
</span>
</li>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
</ul>
What i am really trying to achieve is to get the parentNode of the
textNode and add a class to it.
You don't need to find it, you already have myNodelist[m] whose childNodes you were iterating.
If the condition for index (highest appearance) is met.
You have the node-Value with you here subText[jj].nodeValue, and you already have the obj having the number of appearances by the nodeValue
So, simply add this logic
if ( obj[ subText[jj].nodeValue ] == max )
{
//logic to add the class should be here
myNodelist[m].classList.add("otherclass");
}
subText[jj].nodeValue = subText[jj].nodeValue.replace(/Mock/,"123");
To get the parent of a text node just use myTextNode.parentNode and then use classList to add the class to the parent. This could also be achieved using the treewalker api.
function markMostOccurring(parentSelector, markFn) {
var parent = document.querySelector(parentSelector) || document.body;
var walker = document.createTreeWalker(parent, NodeFilter.SHOW_TEXT, {
acceptNode: node => !!node.nodeValue.trim()
});
var occurenceMap = {};
while(walker.nextNode()) {
var key = walker.currentNode.nodeValue.trim();
var nodes = occurenceMap[key] = occurenceMap[key] || [];
nodes.push(walker.currentNode);
}
var nodes = Object.keys(occurenceMap)
.sort((a, b) => occurenceMap[b].length - occurenceMap[a].length)
.map(key => occurenceMap[key])[0]
.forEach(node => markFn.call(node));
}
markMostOccurring('.container', function() {
this.parentNode.classList.add('mark');
this.nodeValue = this.nodeValue.replace('most', 'cat');
});
.mark {
color: red;
}
<ul class="container">
<li class="item">
<span class="category">
most occurring text
</span>
</li>
<li class="item">
<span class="category">
some text
</span>
</li>
<li class="item">
<span class="category">
some text
</span>
</li>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
<li class="item">
<span class="category">
most occurring text
</span>
</li>
</ul>

How to access all <li> whose id's begins with the same name

I want to access all tags with id="BasketProduct..."
HTML
<ul class ="productdetails">
<li id="BasketProduct-60">...</li>
<li id="BasketProduct-133">...</li>
<li id="BasketProduct-195">...</li>
<li id="BasketProduct-202">...</li>
</ul>
Edited:
var ul = document.getElementsByClassName('productdetails')[0],
i, temp;
for (i = 0; i < ul.children.length; i += 1) {
temp = ul.children[i].id;
if (temp.indexOf('BasketProduct-') > -1) {
// do smth
}
}

Hiding specific elements after creating them with ng-repeat

I'm trying to create a piano on my page using two image files: white-key and black-key.
I've created them, but the black keys on the piano alternate in groups of 2 and 3 and I'd hide the black key images for indices [1, 4(1+3), 8(4+4), 11(8+3), 15(11+4), .., 54]. I'm unsure of how to go about doing this though.
This is how I created them.
HTML:
<div ng-controller="DrawCtrl as draw">
<ul class="white-keys">
<li ng-repeat="t in draw.range(56) track by $index">
<img ng-src={{draw.white_key}} />
</li>
</ul>
<ul class="black-keys">
<li ng-repeat="t in draw.range(55) track by $index">
<img ng-src={{draw.black_key}} />
</li>
</ul>
</div>
JS:
angular.module('app')
.controller('DrawCtrl', function() {
var self = this;
self.piano_back = 'img/background.png';
self.white_key = 'img/midi_white_up.png';
self.black_key = 'img/midi_black_up.png';
self.range = function(num) {
return new Array(num);
};
});
EDIT: Got it working thanks to hansmaad's answer.
HTML:
<ul class="black-keys">
<li ng-repeat="key in draw.keys" ng-switch="key.black">
<img ng-switch-when="true" ng-src={{draw.black_key}} />
<img ng-switch-when="false" ng-src={{draw.black_key}} class="black-hidden" />
</li>
</ul>
JS:
self.keys = [];
var keyGroupOf3 = true;
self.keys.push({black: true}); // first key is shown
var i = 1;
while (i < 54) {
self.keys.push({black: false});
// alwasy followed by at least two
self.keys.push({black: true});
self.keys.push({black: true});
if (keyGroupOf3){
self.keys.push({black: true});
i += 4;
} else {
i += 3;
}
I think you should create your keyboard in the controller as array of keys. You can then use a single ng-repeat to draw all the keys. To draw the right img for a key you can use ng-switch or store the imgage url in the key.
A simple example without images but using ng-class:
http://plnkr.co/edit/kIvRqdkbHHNcUXKzSLZC?p=preview
<div ng-controller="DrawCtrl as draw">
<ul >
<li ng-repeat="key in draw.keys" ng-class="{ 'black' : key.black, 'white' : !key.black}">
</li>
</ul>
</div>
Controller:
function DrawCtrl() {
this.keys = []
for(var i = 0, e = 55; i < e; ++i) {
this.keys.push({
black : isBlackKey(i)
});
}
function isBlackKey(i) {
// your piano logic here
return i % 2 == 0;
}
}
Using ng-switch you could do:
<ul>
<li ng-repeat="key in draw.keys" ng-switch="key.black">
<span ng-switch-when="true">Black key</span>
<span ng-switch-when="false">White key</span>
</li>
</ul>
Edit: This could be a simple, stupid algorithm to fill the keys array:
this.keys = []
var lastWasBlack = true;
var d = 5;
var next = 5;
for(var i = 0, e = 55; i < e; ++i) {
var isBlack = !lastWasBlack;
if (i === next) {
isBlack =!isBlack;
d = d === 5 ? 7 : 5;
next += d;
}
this.keys.push({
black : isBlack
});
lastWasBlack = isBlack;
}
}
http://plnkr.co/edit/kIvRqdkbHHNcUXKzSLZC?p=preview
Have a look at the below plunker. I haven't added any css. But just to hide and show the images you can use this link.
http://plnkr.co/edit/pgFKHShXpeS4EQhoaFTI?p=preview
<ul class="white-keys">
<li ng-repeat="t in draw.range(20) track by $index">
<img ng-src='http://lorempixel.com/g/50/15/technics' ng-hide="($index == 1 || $index == 4 || $index == 8 || $index == 11)"/>
</li>
</ul>
I have used ng-hide to hide the images at specific position.
Is this you are looking for? If not let me know.

how to sort by image src name for all LI under a UL?

I got a UL like this:
<ul id='mylist'>
<li id='1'><img src='kids.jpg'>kids.jpg</li>
<li id='2'><img src='apple.jpg'>apple.jpg</li>
<li id='3'><img src='toys.jpg'>toys.jpg</li>
<li id='4'><img src='love.jpg'>love.jpg</li>
</ul>
I want to sort it using jquery/javascript like this:
<ul id='mylist'>
<li id='2'><img src='apple.jpg'>apple.jpg</li>
<li id='1'><img src='kids.jpg'>kids.jpg</li>
<li id='4'><img src='love.jpg'>love.jpg</li>
<li id='3'><img src='toys.jpg'>toys.jpg</li>
</ul>
May I know how do I write the code?
$(document).ready(function() {
var ul = $('ul#mylist'),
li = ul.children('li');
li.detach().sort(function(a,b) {
return alphabetical($(a).children('img').attr('src'), $(b).children('img').attr('src'));
});
ul.append(li);
});
function alphabetical(a, b)
{
var A = a.toLowerCase();
var B = b.toLowerCase();
if (A < B){
return -1;
}else if (A > B){
return 1;
}else{
return 0;
}
}
<ul id='mylist'>
<li id='1'><img src='kids.jpg'>kids.jpg</li>
<li id='2'><img src='apple.jpg'>apple.jpg</li>
<li id='3'><img src='toys.jpg'>toys.jpg</li>
<li id='4'><img src='love.jpg'>love.jpg</li>
</ul>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
var starting_array = new Array();
var temp_array = new Array();
for(var i = 1 ; i <= 4 ;i++){
starting_array[i] = $('#'+i).find('img').attr('src');
temp_array[i] = $('#'+i).find('img').attr('src');
}
temp_array.sort();
$('#mylist').html('');
var li_data = '';
for(var j=0; j< temp_array.length-1 ; j++ ){
var id = $.inArray(temp_array[j] ,starting_array);
li_data += '<li id="'+ id +'"><img src="'+ temp_array[j] +'" > '+ temp_array[j]+' </li>';
}
$('#mylist').html(li_data);
</script>
You can try this:
var items = $("#mylist > li").detach().get( );
items.sort( srcSort );
$("#mylist").append( items );
function srcSort( a, b ) {
var _a = $(a).children("img").prop("src").toUpperCase();
var _b = $(b).children("img").prop("src").toUpperCase();
if( _a > _b ) return 1;
if( _a < _b ) return -1;
return 0;
}
fiddle here

Categories

Resources