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);
}
}
Related
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.
I have a problem with the function below. It's taking the data from JSON and it's creating a menu item. The problem is when there are more than 2 menu items, and I try to increase the quantity of the first item then the value of the second item is increasing.
function ShowTheMenu(theCategoryId) {
var parentEl = document.getElementById("itemlist");
ClearMenu();
for (let i = 0; i < data.length; i++) {
if (data[i].KategorijaBroj == theCategoryId) {
// MAIN PARENT
var itemBox = document.createElement("div");
itemBox.classList.add("itembox");
var itemImage = document.createElement("img");
itemImage.classList.add("itemimage");
itemImage.src = "/menuitemsimages/" + data[i].Image;
var itemContent = document.createElement("div");
itemContent.classList.add("itemcontent");
var itemTitle = document.createElement("h3");
itemTitle.classList.add("itemtitle");
itemTitle.innerHTML = data[i].Title;
var itemPrice = document.createElement("p");
itemPrice.classList.add("itemprice");
itemPrice.innerHTML = "$" + data[i].Price;
var itemQnt = document.createElement("p");
itemQnt.classList.add("quantity");
itemQnt.innerHTML = "Quantity";
var buttonsBox = document.createElement("div");
buttonsBox.classList.add("divcontrolbtns");
var itemQuantity = 0;
var quantityValue = document.createElement("div");
quantityValue.innerHTML = itemQuantity;
var increaseBtn = document.createElement("div");
increaseBtn.classList.add("controlbtns");
increaseBtn.innerHTML = "+";
increaseBtn.addEventListener("click", function () {
if(itemQuantity < 10) {
itemQuantity++;
}
quantityValue.innerHTML = itemQuantity;
})
var decreaseBtn = document.createElement("div");
decreaseBtn.classList.add("controlbtns");
decreaseBtn.innerHTML = "-";
decreaseBtn.addEventListener("click", function () {
if(itemQuantity > 0) {
itemQuantity--;
}
quantityValue.innerHTML = itemQuantity;
})
var itemAddToCart = document.createElement("button");
itemAddToCart.classList.add("btn-add-to-cart");
itemAddToCart.textContent = "Add to cart";
var itemDesc = document.createElement("p");
itemDesc.classList.add("itemdesc");
itemDesc.innerHTML = data[i].Description;
itemBox.appendChild(itemImage);
itemContent.appendChild(itemTitle);
itemContent.appendChild(itemDesc);
itemContent.appendChild(itemPrice);
itemContent.appendChild(itemAddToCart);
itemContent.appendChild(itemQnt);
buttonsBox.appendChild(increaseBtn);
buttonsBox.appendChild(quantityValue);
buttonsBox.appendChild(decreaseBtn);
itemContent.appendChild(buttonsBox);
itemBox.appendChild(itemContent);
parentEl.appendChild(itemBox);
}
}
}
IMAGE
What should I do in order for the chosen menu item value to be changed?
Try to do something like this bellow. I try to use same HTML structure that you use but to be honest, I suggest that you change a little bit ;)
<!DOCTYPE html>
<html>
<head>
<script>
// Qt
var quantity = new Array();
function ShowTheMenu(theCategoryId) {
// Clear menu
// ClearMenu();
// bt+
increaseBtn = (i) => {
// Item target
let item = document.getElementById('item_' + i);
// Qt target
let qtSpan = item.getElementsByClassName('qt');
// Qt
let qt = parseInt(qtSpan[0].innerHTML);
// Fix some errors
if (qt === undefined || !qt) qt = 0;
// Increase
if (qt < 10) qt++;
// Update
qtSpan[0].innerHTML = qt;
};
// bt-
decreaseBtn = (i) => {
// Item target
let item = document.getElementById('item_' + i);
// Qt target
let qtSpan = item.getElementsByClassName('qt');
// Qt
let qt = parseInt(qtSpan[0].innerHTML);
// Fix some errors
if (qt === undefined || !qt) qt = 0;
// Decrease
if (qt > 0) qt--;
// Update
qtSpan[0].innerHTML = qt;
};
//
var data = new Array();
data[0] = {
Image:
'https://s2.glbimg.com/WcYUQNaattnUf7d8U8MUBfk7loU=/620x430/e.glbimg.com/og/ed/f/original/2015/10/30/pizza.jpg',
KategorijaBroj: 1,
Title: 'Delicious Pizza',
Price: 10,
Description: 'Description test',
};
for (let i = 0; i < data.length; i++) {
if (data[i].KategorijaBroj == theCategoryId) {
// Img
let img = data[i].Image; // '/menuitemsimages/' + data[i].Image;
// Title
let title = data[i].Title;
// Price
let price = '$' + data[i].Price;
// Description
let desc = data[i].Description;
// Qtd
let qt = 2;
// Matriz
let newItem = `<div id="item_${i}" class="itembox">
<div class="itemcontent">
<img src="${img}" border=0 width=100/>
<h3 class="itemtitle">${title}</h3>
<p class="itemprice">${price}</p>
<div class="quantity">
<span>Quantity : </span>
<span class="qt">${qt}</span>
</div>
<div class="controlbtns">
<button class="addbtn" onClick="increaseBtn(${i})">+</button>
<button class="removebtn" onClick="decreaseBtn(${i})">-</button>
</div>
<button class="btn-add-to-cart">Add to cart</button>
<p class="description">${desc}</p>
</div>
</div>`;
// Get the menulist itens
let parentEl = document.getElementById('itemlist');
// Add item
parentEl.insertAdjacentHTML('beforeend', newItem);
}
}
}
</script>
</head>
<body>
<div id="itemlist"></div>
<script>
ShowTheMenu(1);
</script>
</body>
</html>
It's because both items are sharing the same variable, in this case, itemQuantity.
Option 1
If they all should have their own counter I would recommend using an object for tracking this.
const itemQuantity = {
'item1': 2,
'item2': 5
}
if you add some unique class or id to the element you can use this in your onclick event to use as a key. (Where I used 'item1' and 'item2')
Option 2
If you create a function that does everything that's inside your for loop and then just call that function it should also work. This works because every function then creates its own scoped variable of itemQuanity.
Go with whatever options feel best for now. How to manage data in your frontend has a lot of different ways and opinions. You'll quickly discover what works best in what scenario.
What Olavo Mello is mentioning in his answer could still make your code better. using string literals for small HTML snippets is often more readable than using document.createElement(). I would recommend fixing your counter issue first and then look if you could improve your code with Olavo Mello's answer in mind. Good luck :)
How to loop over dynamically generated buttons that has got identical Id for some, and different Id for others,
and create input fields that has value according to the number of buttons.
All buttons has the same class name so that we can use it to loop over them.
For instance :
I got 5 dynamically generated buttons on the page,
3 with identical Id like "55",
and the rest 2 with different Id each other like "14" and "7".
So here it has to create 3 buttons.
dynamically created button 1 (Id = 55) must have value 3 (because there are 3 buttons with Id 55)
dynamically created button 2 (Id = 14) must have value 1 (because there is only 1 button with Id 14)
dynamically created button 3 (Id = 7) must have value 1 (because there is only 1 button with Id 7)
(I know that Id must be unique but I just found it like that, so I'm just maintaining the app for few month adding 2 new features, I'm not allowed to touch anything else as the senior architect dev told me)
("#btn-save").click(function () {
var count = 0;
// Loop over the Id of all these buttons
$("#btn-add-vehicle-item").each(function () {
$("<input class='" + btn-class + "' value='" + myvalue + "' name='VehicleInvoice[" + count + "].VehicleSold' type='hidden' />").insertAfter('#main_div');
count++;
});
});
PS : I'm working on a many to many relationship and cannot have multiple identical Id in the joint table on the Key value side, EF Core is giving this error The instance of entity type 'pppp' cannot be tracked because another instance with the same key value for table... that's why I added a row Quantity Sold in the joint table to hold item number.
I'm following this MS Access tutorial here
IDs should be unique. Use data-* attribute instead. And instruct your senior architect that such issues should be fixed.
Here's an example with those "five buttons" but let's see how to handle that task with the proper data- attributes in place:
const ELNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
const ELS_buttons = document.querySelectorAll("button[data-id]");
const IDS_count = [...ELS_buttons].reduce((ob, el) => {
if (!ob[el.dataset.id]) ob[el.dataset.id] = 1;
else ob[el.dataset.id]++;
return ob;
}, {}); // Will give us something like: {"7": 1, "14": 1, "55": 3}
const ELS_inputs = Object.entries(IDS_count).reduce((DF, [k, v], i) => {
DF.append(ELNew("input", {
class: "my-hidden-input",
title: `Index: ${i} Vehicle ID: ${k} Value: ${v}`,
value: v,
name: `VehiculeInvoice[${i}].VehiculeSold`,
// hidden: true
}))
return DF;
}, new DocumentFragment);
document.querySelector("#mainDiv").append(ELS_inputs);
#mainDiv {padding:10px background: #eee;}
<!-- Dynamically generated buttons example -->
<button data-id="55" type="button">55</button>
<button data-id="14" type="button">14</button>
<button data-id="7" type="button">7</button>
<button data-id="55" type="button">55</button>
<button data-id="55" type="button">55</button>
<div id="mainDiv"></div>
The idea is to create a list of unique IDs:
const mainDiv = document.getElementById("main_div");
/* generating buttons */
const btnClass = "test";
for(let i = 0; i < 10; i++)
{
const button = document.createElement("button");
button.id = Math.floor(Math.random() * 6 + 1);
button.className = btnClass;
button.textContent = "id" + button.id;
mainDiv.appendChild(button);
}
/* get all buttons */
const buttons = document.querySelectorAll("button.test");
const count = {};
//loop through buttons and generate list of unique IDs
for(let i = 0; i < buttons.length; i++)
count[buttons[i].id] = ~~count[buttons[i].id] + 1; //increase count for each id
// loop through unique IDs.
for(let c in count)
{
const input = document.createElement("input");
input.className = btnClass;
// input.type = "hidden";
input.name = "VehiculeInvoice[" + count[c] + "].VehiculeSold";
input.value = count[c];//myvalue?
const span = document.createElement("span");
span.appendChild(input);
span.dataset.id = c; //this will be displayed from CSS
mainDiv.appendChild(span);
}
console.log(count);
/*
$("#btn-save").click(function () {
var count = 0;
// Loop over the Id of all these buttons
$("#btn-add-vehicule-item").each(function () {
$("<input class='" + btn-class + "' value='" + myvalue + "' name='VehiculeInvoice[" + count + "].VehiculeSold' type='hidden' />").insertAfter('#main_div');
count++;
});
});
*/
span
{
display: block;
white-space: nowrap;
}
span:before
{
content: "id" attr(data-id) "=";
}
<div id="main_div"></div>
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
}
}
}
I am attempting to create the mobile view of a restaurant menu. The menu itself is stored in the menu variable which holds data in the form of
let menu = [
[
'Food Section', //i.e Appetizers
['Entry', 'Food Description' , 'Price'],
['Entry', 'Food Description' , 'Price']
]
[
'Food Section', //i.e Soup
['Entry', 'Food Description' , 'Price'],
['Entry', 'Food Description' , 'Price']
],
etc...
I want the website itself to display buttons with the food sections ("Appetizers" button, "Soup" button) and upon clicking said button the appropriate food entries will drop down and become visible. For now I am attempting to just create the buttons and divs of the appropriate entries under each button. I do this by looping through menu and then looping through each menu element. Here is my code:
js:
let menu = [
[
'Appetizers',
['Fried Calamari', "", '$11.95'],
['Mussels', "Marinara, fra diavolo or bianco", '$12.95'],
['Calamari & Mussels', "Fra diavolo or marinara", '$12.95'],
['Hot Antipasto', "Two baked clams, two stuffed shells, two stuffed mushrooms, two fried shrimp & scallops in a seafood sauce", '$14.95'],
],
[
'Soups',
['Chicken Noodle','','$4.95'],
['Minestrone','','$4.95'],
['Lentil','','$5.95'],
['Pasta Fagioli','','$5.95'],
['Cheese Tortellini','','$6.95'],
]
//create html elements by looping through menu variable
for(i = 0; i < menu.length; i++){
for(j = 0; j < menu[i].length; j++){
if(j == 0){
foodSectionText = menu[i][j];
let btn = document.createElement("BUTTON");
btn.innerHTML = foodSectionText;
document.body.appendChild(btn); }
else{
menuEntry = menu[i][j];
console.log(menuEntry);
for(i = 0; i < menuEntry.length; i++){
div = document.createElement("DIV");
div.innerHTML = menuEntry[i];
document.body.appendChild(div);
}
}
}
}
The above code will create:
<button>Appetizers</button>
<div>Fried Calamari</div>
<div></div>
<div>$11.95</div>
But then throws Uncaught TypeError: Cannot read property 'length' of undefined referring to for(j = 0; j < menu[i].length; j++). Why is the second item ['Mussels', "Marinara, fra diavolo or bianco", '$12.95'] (and all subsequent items) not being properly rendered? Also if you have any suggestions as to how to clean up this process feel free to share, I feel I am going about implementing this a terrible way...
In the 3rd for loop, you're reusing the same loop counter i. Try using a different variable name (in my example I used k)
for(let i = 0; i < menu.length; i++){
for(let j = 0; j < menu[i].length; j++){
if(j == 0){
foodSectionText = menu[i][j];
let btn = document.createElement("BUTTON");
btn.innerHTML = foodSectionText;
document.body.appendChild(btn); }
else{
menuEntry = menu[i][j];
console.log(menuEntry);
for(let k = 0; k < menuEntry.length; k++){
div = document.createElement("DIV");
div.innerHTML = menuEntry[k];
document.body.appendChild(div);
}
}
}
}