I am working on a personal project, just practicing on my own and getting to know and familiarized with the language.I am trying to learn by doing so I am creating a shopping cart and I came across a situation that I can not find a proper solution.
I have a list on my shopping cart already rendered of n items. When I 'click' on a plus button to add quantity to an item, it only adds to the quantity to the item that is first on the list and the 'price' of the second item.
Thank you in advance!
function renderCarrito(){
// carritoEl.innerHTML = "";
while(carritoEl.firstChild){
carritoEl.removeChild(carritoEl.firstChild)
};
carrito.forEach((item) =>{
carritoEl.innerHTML += `
<li class="buyItem">
<img src=${item.image}>
<div class="productCartInfo">
<h5 class="prdTitle">${item.title}</h5>
<h6>${item.price}</h6>
<div class="qnty">
<div>
<button class="mbtn">-</button>
<span class="countOfProduct">${item.cantidad}</span>
<button class="pbtn">+</button>
</div>
<div><i class="fas fa-times-circle dltProduct" data-id="${item.id}"></i></div>
</div>
</div>
</li>
`
const plusBtn = document.querySelectorAll('.pbtn');
const minusBtn = document.querySelectorAll('.mbtn');
const count = document.querySelector('.countOfProduct');
plusBtn.forEach(pbtn =>{
pbtn.addEventListener('click', () => {
item.cantidad++;
count.innerHTML = item.cantidad;
carritoSumaTotal();
})});
})
carritoSumaTotal();
}
``
I'm trying to figure out why my function that renders bootstrap 5 cards fails but only after first clicking a pagination button then selecting a drop down menu option. The pagination buttons work fine it seems and the dropdown menu also works fine but only if a pagination button is never clicked.
The problem seems to be in my displayList() function. After clicking a pagination button and clicking a dropdown option the correct array is passed into displayList() but let paginatedItems = items.slice(start, end); returns an empty array. Any help at all would be greatly appreciated.
I've my stripped down code so that hopefully it's easier to read and understand:
const setPosters = [{id:'1',img:'libs/images/pdfFile.jpg',title:'Virus Treatments',author:'Sam Smith',category:'treatments'},{id:'2',img:'libs/images/pdfFile.jpg',title:'Treatments',author:'Dave Smith',category:'illness'},{id:'3',img:'libs/images/pdfFile.jpg',title:'Pain',author:'Sam Smith',category:'illness'},{id:'4',img:'libs/images/pdfFile.jpg',title:'Virus Treatments',author:'Bob Burke',category:'illness'},{id:'5',img:'libs/images/pdfFile.jpg',title:'Pain Treatments',author:'James Frank',category:'cures'},{id:'6',img:'libs/images/pdfFile.jpg',title:'Sinus Treatments',author:'Ted Reed',category:'illness'},{id:'7',img:'libs/images/pdfFile.jpg',title:'Migrain Treatments',author:'Ted Reed',category:'remedy'},{id:'8',img:'libs/images/pdfFile.jpg',title:'Flu Treatments',author:'Ted Reed',category:'remedy'},{id:'9',img:'libs/images/pdfFile.jpg',title:'Virus Treatments',author:'James Frank',category:'remedy'},{id:'10',img:'libs/images/pdfFile.jpg',title:'Flu Treatments',author:'Ralph Barnes ',category:'remedy'},{id:'11',img:'libs/images/pdfFile.jpg',title:'Virus Treatments',author:'Thomas Smith',category:'cures'},{id:'12',img:'libs/images/pdfFile.jpg',title:'Pain Treatments',author:'Ralph Barnes',category:'remedy'},{id:'13',img:'libs/images/pdfFile.jpg',title:'Virus Treatments',author:'Sam Smith',category:'treatments'},{id:'14',img:'libs/images/pdfFile.jpg',title:'Treatments',author:'Dave Smith',category:'illness'},{id:'15',img:'libs/images/pdfFile.jpg',title:'Pain',author:'Sam Smith',category:'illness'},]
// this continues for a total of about 80 cards in my local version
let posters;
const cardElement = $('#cards');
const paginationElement = $('#pagination');
let currentPage = 1;
let rows = 10;
let page_count;
///////////\\\\\\\\\\\
// **** Functions ***\\
//////////\\\\\\\\\\\\\\
function displayList(items, wrapper, rows_per_page, page) {
wrapper.html("");
page--;
console.log('displayList', items);
let start = rows_per_page * page;
let end = start + rows_per_page;
let paginatedItems = items.slice(start, end);
console.log('paginatedItems:', paginatedItems);
for (let i = 0; i < paginatedItems.length; i++) {
wrapper.append(`
<div class="col gx-2">
<div class="card">
<img
src=${paginatedItems[i].img}
class="card-img-top"
alt="..."
/>
<div class="card-body p-1">
</div>
<div class="card-footer">
Title: ${paginatedItems[i].title}
Category: <strong>${paginatedItems[i].category}</strong><br>
Author: ${paginatedItems[i].author}<br>
id: ${paginatedItems[i].id}<br>
</div>
</div>
</div>
`)
};
};
function setupPagination(items, wrapper, rows_per_page) {
wrapper.html("");
page_count = Math.ceil(items.length / rows_per_page) + 1;
for (let i = 1; i < page_count; i++) {
wrapper.append(`<li class="page-item"><a class="page-link" href="#">${i}</a></li>`);
};
};
/////////////////////\\\\\\\\\\\\\\\\\\\\
// **** Posters By Category Dropdown ***\\
////////////////////\\\\\\\\\\\\\\\\\\\\\\
//Adds Categories to Dropdown Select Options
uniqCatergoriesArray = uniqCatergories(setPosters, it => it.category);
function uniqCatergories(data, key) {
return [...new Map(data.map(x => [key(x), x])).values()]
}
for (var i = 0; i < uniqCatergoriesArray.length; i++) {
$('#selPosterCat').append($('<option>', {
value: uniqCatergoriesArray[i].category,
text: uniqCatergoriesArray[i].category,
}));
}
//Displays Posters By Category
$('#selPosterCat').on('change', function() {
console.log($('#selPosterCat').val());
$('#textSearchResult').html(' ');
$('#inlineFormInput').val('');
if ($('#selPosterCat').val() === 'all') {
posters = setPosters.filter(item => item);
displayList(posters, cardElement, rows, currentPage);
setupPagination(posters, paginationElement, rows);
} else {
posters = setPosters.filter(item => item.category === $('#selPosterCat').val());
console.log('dropdown', posters);
displayList(posters, cardElement, rows, currentPage);
setupPagination(posters, paginationElement, rows);
}
});
/////////////////\\\\\\\\\\\\\
// **** Pagination Click ***\\
/////////////////\\\\\\\\\\\\\\
$(document).on("click", "ul.pagination li a:not(.static)", function(e) {
currentPage = parseInt($(this).text());
posters = setPosters.filter(item => item);
displayList(posters, cardElement, rows, currentPage);
});
posters = setPosters.filter(item => item)
displayList(posters, cardElement, rows, currentPage);
setupPagination(posters, paginationElement, rows);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- *** Main Content Container *** -->
<div class="container-fluid" id="mainContainer">
<div id="mainCardContainer">
<!-- *** Search Bar *** -->
<div class="container-fluid">
<div class="row">
<div class="col">
<form id="form-id">
<div class="mb-3 d-flex justify-content-center" style="margin-top: 5vh;">
<select id="selPosterCat" class="form-select-sm w-25" aria-label="Default select example" style="border-right: none; border-width: 1px; height: 2rem;">
<option value="all" selected>All Categories</option>
<!-- other options added here by javaScript -->
</select>
</div>
</form>
</div>
</div>
<div class="row row-cols-1 row-cols-lg-5 row-cols-sm-2 g-4" id="cards">
<!-- individual cards added here by javaScript -->
</div>
<!-- *** Pagination Bar *** -->
<div class="container-fluid mt-3 pe-0 me-0">
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-end">
<li class="page-item" id="previousBtn">
<a class="page-link static" href="#" tabindex="-1" aria-disabled="true" id="">Previous</a>
</li>
<div class="d-flex" id="pagination">
<!-- page numbers added here by javaScript -->
</div>
<li class="page-item" id="nextBtn">
<a class="page-link static" id="" href="#">Next</a>
</li>
</ul>
</nav>
</div>
Just change this code:
item => item.category === $('#selPosterCat').val()
With this:
item => item.category = $('#selPosterCat').val()
and be sure from adding these links respectively:
https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js
https://cdn.jsdelivr.net/npm/bootstrap#5.0.1/dist/css/bootstrap.min.css
https://cdn.jsdelivr.net/npm/bootstrap#5.0.1/dist/js/bootstrap.bundle.min.js
http://jsfiddle.net/rewan_95/107zxr3g is the fiddle I tested on.
Note: don't forget to add the above links for testing on jsfiddle
I'm currently trying to display an individual.html page based off what the user clicks on a products.html page. For example, clicking on product1 would show the individual page for product1 and clicking on product2 would show the individual page for product2 etc...
I currently have a UI class in my app.js file which holds the logic for displaying information.
There is a function in there called displayIndividualProject() which has an event listener that says, "If a card is clicked (if (event.target.classList.contains('img-container'))), then inject this HTML structure into the individual.html" page. However, after I click on it, it's not injecting the sequence.
Also, displayIndividualProduct is meant for the individual.html page while displayProducts is meant for the product.html page.
Here is what part of my UI class looks like:
const individualProductsDOM = document.querySelector('.single-product');
class UI{
displayIndividualProduct(){
document.addEventListener("click", event => {
if (event.target.classList.contains('img-container'))
individualProductsDOM.innerHTML =
`
<div class='section-title'>
<h2>${product.title}</h2>
</div>
<div class='indi-img-container'>
<img src=${product.image} data-id='${product.id} alt="">
</div>
<div class="product-footer">
<h3>Estimated Cost: $ <span class='item-total'>0</span></h3>
<button class='bag-btn-2' data-id='${product.id}'>
<i class='fas fa-shopping-cart'></i>
add to cart
</button>
</div>
`
})
individualProductsDOM.innerHTML += `injected`;
}
displayProducts(products){
let result = '';
products.forEach(product => {
result += `
<article class="product" data-id='${product.id}'>
<div class='img-container'>
<a href='/individual.html'>
<img src=${product.image} alt="product" class='product-img' data-id='${product.id}'>
<button class='bag-btn' data-id='${product.id}'>
<i class='fas fa-shopping-cart'></i>
add to cart
</button>
</a>
</div>
<h3>${product.title}</h3>
<h4>$${product.price}/roll</h4>
</article>
`
});
//insert the products into the productsDOM
productsDOM.innerHTML = result;
}
}
and this is being called at the bottom of my JS through ui.displayIndividualProduct();
document.addEventListener("DOMContentLoaded", () => {
const ui = new UI();
const products = new Products();
// setup app
ui.setupAPP();
//get all products
products.getProducts().then(products => {
//first display, then save, and then connect the add cart buttons
ui.displayProducts(products);
Storage.saveProducts(products);
}).then( () => {
ui.getBagButtons();
});
ui.displayIndividualProduct();
});
any help would be appreciated!
I figured out how to change the icon when more elements are added, but I can't figure out to how return it to the original icon while the cart is empty.
Javascript
let cartItems = document.getElementsByClassName('cart-container')[0];
if (cartItems.childElementCount <= 1) {
let cartBtn = document.getElementsByClassName('cart-btn')[0]
cartBtn.innerHTML = `
<i class="fa fa-cart-plus cart-btn text-danger"></i>`
}
HTML
<h1 class="cart-btn">
<i class="fa fa-shopping-cart"></i>
</h1>
<div class="container cart-container d-flex flex-column pb-5">
<div class="row mt-5 mb-4">
<div class="col">
</div>
</div>
</div>
I have a shopping cart button on a navbar that I need to switch between different states depending on if the cart is empty or not. I figured out how to change it to one state when an item was added to the cart, but couldn't figure out how to change it back to the original state when I emptied the cart. However, I used this code to accomplish that task.
Javascript
function checkNavBtn() {
let cartItems = document.getElementsByClassName('cart-container')[0];
let cartBtn = document.getElementsByClassName('fa-shopping-cart')[0];
if (cartItems.childElementCount >= 0) {
cartBtn.classList.add('fa-cart-plus', 'text-danger');
} if (cartItems.childElementCount <= 0) {
cartBtn.classList.remove('fa-cart-plus', 'text-danger');
}
}
I am making a Todo list using HTML, CSS and jQuery. So basically when the person types an activity and presses the '+' button it gets added to the list along with a 'Delete'(Font Awesome Recycle Bin) icon so that the user can delete the activity. I have implemented this using the .append() function. However, when a user adds the first item there is one delete button. However for every other list the number of delete buttons multiply. (Eg. when the user adds the second item there are two delete buttons for that item, and when they add the third item there are three delete buttons for that item). I can't understand why this is happening and what is the best way to fix this?
I have used .append() on the .listInput and appended the .newItem.
I have then used .append() on the .newItem and appended the can icon.
$(".enter").click(function() {
var $item = $('input[name=add]').val();
if ($item.length > 0) {
$(".listInput").append('<li class="newItem animated fadeIn">' + $item + '</li>');
$('.newItem').append('<i class="animated fadeIn far fa-trash-alt fa-1x"></i>');
} else {
alert("Enter an acitvity to add");
}
})
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="takeInput">
<input type="text" name="add" value="Add Your Item Here">
<i class="enter fas fa-plus fa-3x"></i>
</div>
<ul class="listInput">
</ul>
I want only one trash icon for each list item.
$('.newItem').append() will append something to all elements with the class newItem, not just the one you just added. To fix that just use a single append:
$(".enter").click(function() {
var $item = $('input[name=add]').val();
if ($item.length > 0) {
$(".listInput").append('<li class="newItem animated fadeIn">' + $item + '<i class="animated fadeIn far fa-trash-alt fa-1x"></i></li>');
} else {
alert("Enter an acitvity to add");
}
})
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="takeInput">
<input type="text" name="add" value="Add Your Item Here">
<i class="enter fas fa-plus fa-3x"></i>
</div>
<ul class="listInput">
</ul>
Please try this
var $item = $('input[name="add"]').val();
The problem is that $('.newItem') refers to any element that has that class. For example, if you have five items on the list they will all have the class new item. If you were to add another item (that makes six items), then you are adding a bin icon to each element with class 'newItem'
$(".enter").click(function() {
var $item = $('input[name=add]').val();
if ($item.length > 0) {
$(".listInput").append('<li class="newItem animated fadeIn">' + $item + '</li>' + '<i class="animated fadeIn far fa-trash-alt fa-1x"></i>');
} else {
alert("Enter an acitvity to add");
}
})
$(".enter").click(function() {
let item = $('input[name=add]').val();
let li = $('<li class="newItem animated fadeIn"/>');
let iconTrash = $('<i style="margin-left:1em;" class="animated fadeIn far fa-trash-alt fa-1x"/>')
if (item.length >= 0) {
li.append(item,iconTrash)
$(".listInput").append(li);
} else {
alert("Enter an acitvity to add");
}
})
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="takeInput">
<input type="text" name="add" value="Add Your Item Here">
<i class="enter fas fa-plus fa-3x"></i>
</div>
<ul class="listInput">
</ul>
The problem is the trash icon is added to all the elements that have the class 'newItem'. So you have to create a li(list item) element and append it to the ul(unordered list) element. Then create the icon and append it to the created list item element. You can create element using the document.createElement(tagName) function. and append it using javascript or jquery