How could I add the next/ previous page buttons to an Array in JavaScript?
I have this Array:
let products = {
data: [
{
productName: "Product1",
},
{
productName: "Product2",
},
{
productName: "Product3",
},
{
productName: "Product4",
},
{
productName: "Product5",
},
{
multiple other products
},
],
};
After 5 products, a new page should begin. I have done this using the following JavaScript code:
const nav = document.getElementById('nav');
const content = document.getElementById('content');
let pageIndex = 0;
let itemsPerPage = 3;
loadItems();
function loadItems() {
content.innerHTML = "";
for (let i = pageIndex * itemsPerPage; i < (pageIndex * itemsPerPage) + itemsPerPage; i++) {
if (!items[i]) break;
const item = document.createElement('div');
item.innerHTML = `
<div>
<img src="${items[i].src}"/>
</div>
<div>
<button>${items[i].desc}</button>
</div>
`;
content.append(item);
}
loadPageNav();
}
function loadPageNav() {
nav.innerHTML = "";
for (let i = 0; i < items.length / itemsPerPage; i++) {
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = i + 1;
button.addEventListener('click', (e) => {
pageIndex = e.target.innerHTML - 1;
loadItems();
});
if (i === pageIndex) {
/*button.style.fontSize = "2rem";*/
}
nav.append(button);
}
}
I now also want to include the next and previous buttons. This means that when the user clicks the next button, the next page should be shown. When the user clicks the previous page button, the previous page should be shown.
When the first page is shown, the previous page button should be a different colour. When the last page is shown, the next page button should be a different colour.
Related
My pagination System currently looks like this:
What my pagination system currently looks like
However, I only want 10 page links to appear at a time. Instead of all of the links.
I have this code:
const nav = document.getElementById('nav');
const content = document.getElementById('content');
let pageIndex = 0;
let itemsPerPage = 3;
let finalPage = Math.ceil(items.length / itemsPerPage) - 1;
console.log(finalPage)
loadItems();
function loadItems() {
content.innerHTML = "";
for (let i = pageIndex * itemsPerPage; i < (pageIndex * itemsPerPage) + itemsPerPage; i++) {
if (!items[i]) break;
const item = document.createElement('div');
item.innerHTML = `
<div>
<img src="${items[i].src}"/>
</div>
<div>
<button>${items[i].desc}</button>
</div>
`;
content.append(item);
}
firstPage();
minusPage();
loadPageNav();
plusPage();
lastPage();
}
function loadPageNav() {
for (let i = 0; i < items.length / itemsPerPage; i++) {
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = i + 1;
button.addEventListener('click', (e) => {
pageIndex = e.target.innerHTML - 1;
loadItems();
});
nav.append(button);
}
}
function plusPage() {
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = "›";
button.addEventListener('click', () => {
pageIndex = pageIndex + 1;
loadItems();
});
nav.append(button);
if (pageIndex === finalPage) {
button.disabled = true;
}
}
function minusPage() {
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = "‹";
button.addEventListener('click', () => {
pageIndex = pageIndex - 1;
loadItems();
});
nav.append(button);
if (pageIndex === 0) {
button.disabled = true;
}
}
function firstPage() {
nav.innerHTML = "";
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = "«";
button.addEventListener('click', () => {
pageIndex = 0;
loadItems();
});
nav.append(button);
if (pageIndex === 0) {
button.disabled = true;
}
}
function lastPage() {
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = "»";
button.addEventListener('click', () => {
pageIndex = finalPage;
loadItems();
});
nav.append(button);
if (pageIndex === finalPage) {
button.disabled = true;
}
}
This code produces the output shown above. However, I want to produce this output:
What my pagination system should look like
From my understanding, the loadPageNav function is the one that draws your page numbers. Pay attention to the maximum value your for loop goes too.
For example if you have 100 items (items.length = 100) and want to display only 5 items per page then
items.length / itemsPerPage is 100 / 5 = 20.
You have 20 pages and in your loop you create and add a button for each of those. If you want to limit the number of buttons drawn, then you need to limit the maximum value you assign to i.
I have created an Array of objects. This Array contains thousands of objects.
For example:
let products = [
{name: "Name 1"},
{name: "Name 2"},
{name: "Name 3"},
{name: "Name 4"},
{name: "Name 5"}]
For each object, I have created a card using this code:
for (let i of products) {
//Create Card
let card = document.createElement("div");
//Card should have category and should stay hidden initially
card.classList.add("card", i.category, "hide");
// Add name to card
let name = document.createElement("h1");
name.innerText = i.name();
card.appendChild(name);
document.getElementById("products").appendChild(card);
}
I have dynamically paginated these objects to only show a maximum of 100 cards per page. I have done this using the following code:
let itemsPerPage = 100;
function loadPageNav() {
for (let i = 0; i < items.length / itemsPerPage; i++) {
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = i + 1;
button.addEventListener('click', (e) => {
pageIndex = e.target.innerHTML - 1;
loadItems();
});
nav.append(button);
}
}
This works correctly. However, there are too many buttons on the page. If I am on page 10, all of the buttons show up. However, I only want the buttons containing pages 8 to 12 to show up.
The buttons currently look like this:
How the buttons look now
However, the buttons should look like this:
How the buttons should look
How could I hide the buttons that do not need to be shown?
This needs to be done in Vanilla JavaScript
You should use pageIndex for starting point like this:
let itemsPerPage = 100;
function loadPageNav() {
for (let i = pageIndex - 2; i <= pageIndex + 2; i++) { // <-- Changed here
const button = document.createElement('button');
button.classList.add('btn');
button.innerHTML = i + 1;
button.addEventListener('click', (e) => {
pageIndex = e.target.innerHTML - 1;
loadItems();
});
nav.append(button);
}
}
I want to create a star rating system that has 5 stars. You can not select a half star, only a whole one. I want to achieve the following: If the user clicks on the star, the cilcked one and the other before it should be activated, and if the user clicks on a lower star deactivate all the stars after the selected one.
Here is what I got so far: The user can select 4 stars out of five (on the fifth click I have a bug which should be solved).
PS: I am working with SVG images but it would be way too ugly to insert in so the [ ] are the empty stars (the default), and the [X] are the selected (active) stars.
Heres my code:
for (let i = 1; i <= 5; i++) { document.getElementById("w__stars").innerHTML += `<span class="r__icon">[ ]</span>`; }
var icon = document.getElementsByClassName("r__icon");
for (let i = 0; i < icon.length; i++) {
icon[i].addEventListener("click", function (e) { console.log("--");
for (let j = 0; j < i+1; j++) {
console.log("i: " +i); console.log("j: "+(j+1)); console.log("Rest: "+ (j+(5-(i+1))));
icon[j].innerHTML = `[X]`;
icon[i+(5-(i+1))].innerHTML = `[ ]`;
}
});
}
<div class="flex flex-row product-star-con" id="w__stars"></div>
Your method just needs a different approach. For instance that inner loop is unnecessary if you are to place this in there icon[j].innerHTML = '[X]'.. which can be placed just within the outer loop.
Also the unnecessary calculations are making the task seem harder than it actually is. And since this is a loop, the i variable will always have the highest value within the loop, since there is no break statement in there
The method below targets the next elements and previous elements relative to the one being clicked at the moment and applies the appropriate 'innerHTML' to them
// Function to get previous and next siblings of the target element
function getSiblings(element, type){
var arraySib = [];
if ( type == 'prev' ){
while ( element = element.previousSibling ){
arraySib.push(element);
}
} else if ( type == 'next' ) {
while ( element = element.nextSibling ){
arraySib.push(element);
}
}
return arraySib;
}
for (var i = 1; i <= 5; i++) { document.getElementById("w__stars").innerHTML += `<span class="r__icon">[ ]</span>`; }
var icon = document.getElementsByClassName("r__icon");
for (var i = 0; i < icon.length; i++) {
icon[i].addEventListener("click", function (e){
this.innerHTML = `[X]`;
var prev = getSiblings(this, 'prev')
var next = getSiblings(this, 'next')
// populate previous siblings
for(p = 0; p < prev.length; p++){
prev[p].innerHTML = `[X]`
}
// clear next siblings
for(n = 0; n < next.length; n++){
next[n].innerHTML = `[]`
}
});
}
<div class="flex flex-row product-star-con" id="w__stars"></div>
Another approach:
// Setting stars
const stars = [];
for (let i = 0; i <= 4; i++) {
stars.push({
active: false,
index: i
});
}
const renderStars = (parentElement, stars, activeContent, notActiveContent) => {
parentElement.innerHTML = '';
stars.forEach(({ active, index }) => {
parentElement.innerHTML += `
<span class="r__icon">${active ? activeContent : notActiveContent}</span>`;
});
Array.from(parentElement.querySelectorAll('.r__icon')).forEach((item, itemIndex) => {
const star = stars.find(({ index }) => index === itemIndex);
stars[star.index].element = item;
item.addEventListener('click', (e) => {
const itemElement = e.target;
const starIndex = stars.findIndex(({ element }) => element === itemElement);
if (starIndex === -1) {
return;
}
const toActive = stars[starIndex].active !== true;
stars = stars.map(star => {
if (toActive) {
// Set items before index to true, and after to false
if (star.index <= starIndex) {
return {
...star,
active: true
};
}
return {
...star,
active: false
};
} else {
// Set items after index to false, and before to true
if (star.index >= starIndex) {
return {
...star,
active: false
};
}
return {
...star,
active: true
};
}
});
renderStars(parentElement, stars, activeContent, notActiveContent);
});
});
};
const setupStars = (stars, activeContent, notActiveContent) => {
const parentElement = document.getElementById("w__stars");
if (!parentElement) {
return;
}
renderStars(parentElement, stars, activeContent, notActiveContent);
};
setupStars(stars, '[X]', '[ ]');
<div class="flex flex-row product-star-con" id="w__stars"></div>
I made an image slider that work, but now I'm trying to add an animation effect to it, and I believe JavaScript may be the answer for that.
I'm trying to add the possibility to click the arrow buttons and have the image slide left or right depending on whether the left or right arrow is being clicked.
Is that possible.
Here is my HTML file.
<body>
<div id="hcg-slider-1" class="hcg-slider">
<div class="hcg-slide-container">
<div class="hcg-slider-body">
<a class="hcg-slides animated" style="display:block">
<span class="hcg-slide-number">1/5</span>
<img src="https://www.html-code-generator.com/images/slider/1.png" alt="image 1">
<span class="hcg-slide-text">image 1</span>
</a>
</div>
<a class="hcg-slide-prev" href="#">❮</a>
<a class="hcg-slide-next" href="#">❯</a>
</div>
<div class="hcg-slide-dot-control"></div>
</div>
<script>
(function(){
//If you want to include more images, add the link name and URL of the image in the array list below.
let images_list = [
{"url":"photos/headers/ABY-header.png",
"link":"",
"name": "just text"},
{"url":"photos/headers/TMN-header.png",
"link":"",
"name": "just text"},
{"url":"photos/headers/TW-header.png",
"link":"",
"name": "just text"},
{"url":"photos/headers/NY-header.png",
"link":"",
"name": "just text"},
];
let slider_id = document.querySelector("#hcg-slider-1");
// append all images
let dots_div = "";
let images_div = "";
for (let i = 0; i < images_list.length; i++) {
// if no link without href="" tag
let href = (images_list[i].link == "" ? "":' href="'+images_list[i].link+'"');
images_div += '<a'+href+' class="hcg-slides animated"'+(i === 0 ? ' style="display:block"':'')+'>'+
'<span class="hcg-slide-number">'+(i+1)+'/'+images_list.length+'</span>'+
'<img src="'+images_list[i].url+'" alt="'+images_list[i].name+'">'+
'<span class="hcg-slide-text">'+images_list[i].name+'</span>'+
'</a>';
dots_div += '<span class="hcg-slide-dot'+(i === 0 ? ' dot-active':'')+'" data-id="'+i+'"></span>';
}
slider_id.querySelector(".hcg-slider-body").innerHTML = images_div;
slider_id.querySelector(".hcg-slide-dot-control").innerHTML = dots_div;
let slide_index = 0;
let images = slider_id.querySelectorAll(".hcg-slides");
let dots = slider_id.querySelectorAll(".hcg-slide-dot");
let prev_button = slider_id.querySelector(".hcg-slide-prev");
let next_button = slider_id.querySelector(".hcg-slide-next");
function showSlides() {
if (slide_index > images.length-1) {
slide_index = 0;
}
if (slide_index < 0) {
slide_index = images.length-1;
}
for (let i = 0; i < images.length; i++) {
images[i].style.display = "none";
dots[i].classList.remove("dot-active");
if (i == slide_index) {
images[i].style.display = "block";
dots[i].classList.add("dot-active");
}
}
}
prev_button.addEventListener("click", function(event) {
event.preventDefault();
slide_index--;
showSlides();
}, false);
next_button.addEventListener("click", function(event){
event.preventDefault();
slide_index++;
showSlides();
}, false);
function dot_click(event) {
slide_index = event.target.dataset.id;
showSlides();
}
for (let i = 0; i < dots.length; i++) {
dots[i].addEventListener("click", dot_click, false);
}
})();
</script>
I managed to add a sliding animation using JavaScript. Here's a good guide as to how it can be done.
https://www.cssscript.com/animated-image-slider/
This is the code I added.
const content = document.querySelector(".content");
const slider = document.querySelector(".slider");
const sliderImage = Array.from(document.querySelectorAll(".slider-image"));
const btnChevron = document.querySelectorAll(".btn-chevron");
let i = 0;
let reset = (container, clase) => {
container.forEach(item => item.classList.remove(clase));
}
let createInfo = text => {
const sliderInfo = document.createElement("p");
sliderInfo.className = "slider-info";
sliderInfo.textContent = text;
content.appendChild(sliderInfo);
};
let createIndicators = () => {
const container = document.createElement("div");
container.className = "indicator";
content.appendChild(container)
sliderImage.forEach(image => {
let indicator = document.createElement("p");
indicator.textContent = sliderImage.indexOf(image) + 1;
container.appendChild(indicator);
})
}
let Image = (index) => {
const indicators = document.querySelectorAll('.indicator p');
const sliderInfo = document.querySelector('.slider-info');
sliderImage[index].classList.add('slider-image-active');
reset(indicators, 'indicator-active');
indicators[i].classList.add('indicator-active');
if (content.hasElement(".slider-info")) return sliderInfo.textContent = sliderImage[index].dataset.info;
createInfo(sliderImage[index].dataset.info);
}
let setPosition = (index) => {
let width = sliderImage[index].getBoundingClientRect().width;
slider.style.transform = `translateX(-${width * index}px)`;
}
let moveImage = () => {
if (i === sliderImage.length) {
i = 0; // Si el contador ya llego al ultimo item, lo manda al primer item.
} else if (i == -1) {
i = sliderImage.length - 1; // Si llego al primero lo manda hasta el ultimo.
}
reset(sliderImage, 'slider-image-active');
setPosition(i);
Image(i);
};
btnChevron.forEach(btn => {
btn.addEventListener('click', () => {
if (btn.dataset.action == "right") {
i++;
return moveImage();
}
i--;
return moveImage();
})
})
createIndicators();
Image(i);
Note: I know there may be ways to do this in other languages but I have only learned javascript.
I have an array of objects (food items in this case, each item has a name property). I have this code in a for loop that makes buttons for each item in the array (if the first item in the array has a name of cake then cake's button is called cake, if the item is called fries then the buttons name is fries). I want the user to be able to click the button for each item only once, and when that button is clicked, I want to display a list of each item clicked. The reason why I have var click = item[i].name is because I want each button to have the name of the item. This code makes a button for item in the array but it does not list the items clicked on. Here is my code:
HTML
<html>
<head>
</head>
<body>
<p id="likes">Likes: </p>
</body>
</html>
JAVASCRIPT
var items=[
{
name:"cake",
price:12
},
{
name:"fries",
price:10
},
{
name:"apple",
price:11
}
];
window.onload = function() {
for (var i = 0; i < items.length; i++) {
var btnItems = document.createElement("button");
btnItems.id = "btnItems";
btnItems.innerHTML = "Items";
var clicks = items[i].name;
btnItems.onclick = function () {
el.disabled = true;
clicks += items[i].name + i;
document.getElementById("clicks").innerHTML = "Items Clicked" + clicks;
}
}
Style your view as you wish but this should answer your problem
var items = [{
name: "cake",
price: 12
},
{
name: "fries",
price: 10
},
{
name: "apple",
price: 11
}
];
for (let i = 0; i < items.length; i++) {
const btn = document.createElement("button");
btn.id = "btnItems";
btn.textContent = items[i].name;
btn.onclick = function(el) {
// disable your button immediately upon click
el.target.disabled = true;
// create list element and assign value
const li = document.createElement('li');
li.textContent = items[i].name
// append list element to your <ul> list
document.getElementById('list-section').appendChild(li);
}
// append button to the DOM
document.body.appendChild(btn)
}
<ul id="list-section">
</ul>
HTML code:
I created a div to append the buttons in it.
<html>
<head>
</head>
<body>
<p id="likes">Likes: </p>
<p id="clicks"></p>
<div id="btn-container">
</div>
</body>
</html
>
Js code:
var items=[
{
name:"cake",
price:12
},
{
name:"fries",
price:10
},
{
name:"apple",
price:11
}
];
for (var i = 0; i < items.length; i++) {
var btnItems = document.createElement("button");
btnItems.id = "btnItems"+i;
var clicks = items[i].name;
btnItems.innerHTML = clicks;
document.getElementById("btn-container").appendChild(btnItems);
console.log(btnItems);
btnItems.addEventListener('click',function (el) {
alert('here');
el.disabled = true;
clicks += items[i].name + i;
document.getElementById("clicks").innerHTML = "Items Clicked" + clicks;
});
}
As you have not provided a reproducible example I cannot test this, however, you should be able to use something like this. Please take note of the comments and amend where necessary.
window.onload = function() {
for (var i = 0; i < items.length; i++) {
var btnItem = document.createElement("button");
const name = item[i].name;
// Set the button id
btnItem.id = `btnItem-${name}`;
// Set the button text to the item name
btnItem.innerHTML = name
btnItem.addEventListener('click', function (event) {
event.target.disabled = true;
// Do whatever you want here, e.g. add "name" to a list
}
}
}