I have products and a cart. Each product has an "Add to cart" button and when you click it, it'll add the product to the cart and the inner text of the button will be "In cart" and the button will be disabled. My problem is that I can't figure out how to enable the button and change the inner text back to "Add to cart" after I remove the product from the cart or clear it.
This is the JS for adding the product:
let addBtns = document.getElementsByClassName("bag-btn");
for (let i = 0; i < addBtns.length; i++) {
const btn = addBtns[i];
btn.addEventListener("click", addToCart);
}
function addToCart(e) {
const button = e.target;
button.innerText = "In Cart";
button.disabled = true;
const title = button.parentElement.nextElementSibling.textContent;
const price =
button.parentElement.nextElementSibling.nextElementSibling.children[0]
.textContent;
const img = button.parentElement.children[0].src;
addItemToCart(title, price, img);
}
function addItemToCart(title, price, img) {
const newRow = document.createElement("div");
newRow.classList.add("cart-item");
newRow.innerHTML = `
<img src="${img}" alt="product" srcset="" />
<div>
<h4>${title}</h4>
<h5>${price}</h5>
<span class="remove-item">Remove</span>
</div>
<div>
<i class="fas fa-chevron-up"></i>
<p class="item-amount">1</p>
<i class="fas fa-chevron-down"></i>
</div>`;
cartContent.append(newRow);
}
this is the remove product function:
cartContent.addEventListener("click", (e) => {
if (e.target.classList.contains("remove-item")) {
let removeItem = e.target;
cartContent.removeChild(removeItem.parentElement.parentElement);
SO, how to change the button text and functionality back to normal after I remove the product from the cart? Any help would be appreciated.
Why do you not do the same delegation for the add as you do for the remove?
I do not have your HTML, but something like this
cartContent.addEventListener("click", (e) => {
const tgt = e.target;
if (tgt.classList.contains("remove-item")) {
tgt.closest("whatever container").remove();
tgt.closest("whatever container has button").querySelector(".bag-btn").textContent="Add to cart";
}
else if (e.target.classList.contains("bag-btn")) addToCart(tgt)
})
and have
function addToCart(button) {
// const button = e.target;
All those parentElement.nextElementSibling.nextElementSibling.children[0] are horrific
Instead use button.closest("whatever container").querySelector("some selector")
So basically I have a Grocery List and an Inventory List. I want to be able to:
Add an item to either list.
Remove an item from either list.
Move an item from one list to the other.
Each list has its own array, and when you "Add an item" to either list, I have a function (nodeConstructor) that pushes the item to its corresponding array and builds an 'item element' in the desired div (the grocery list or inventory list).
The problem that I'm having is in moving an item from one list to the other. When you click the 'move' button, my 'nodeConstructor' function is supposed to be called and it should basically recreate the selected element in the other list. It kind of does that, except the item value (inputVal) renders as 'undefined' in the div rather than the value of the item that was moved (however it moves from array to array correctly).
The other problem is that moving an item from the Grocery List to the Inventory List correctly splices the item from the Grocery List array and pushes it to the Inventory List array, but moving an item from the Inventory List to the Grocery List neither splices the item from the array nor moves it to the Grocery List array (I'm thinking it has something to do with the order of conditionals being checked but I'm not sure).
If anyone could show me where I'm going wrong it would be greatly appreciated. Also, any suggestions on an easier way to achieve this functionality would be welcomed.
Here is a link to the Codepen that demonstrates my issue: https://codepen.io/TOOTCODER/pen/OJXQKGp?editors=1011
HTML
<label for="groceryInput">Add Grocery Item: </label>
<input id="groceryInput" type="text">
<button id="groceryInputBtn">Submit</button>
<label for="inventoryInput">Add Inventory Item: </label>
<input id="inventoryInput" type="text">
<input id="inventoryInputBtn" type="submit">
<div class="outputDiv" id="arr1Output"><h1>Grocery</h1></div>
<div class="outputDiv" id="arr2Output"><h1>Inventory</h1></div>
CSS
.outputDiv{
width: 200px;
height: 200px;
border: 1px solid black;
margin: 25px 0 0 25px;
}
.outputDiv h1{
text-align: center;
text-decoration: underline;
}
JavaScript
const groceryInput = document.querySelector("#groceryInput");
const groceryInputBtn = document.querySelector("#groceryInputBtn");
const inventoryInput = document.querySelector("#inventoryInput");
const inventoryInputBtn = document.querySelector("#inventoryInputBtn");
const arr1Output = document.querySelector("#arr1Output");
const arr2Output = document.querySelector("#arr2Output");
const groceryList = [];
const inventoryList = [];
//add grocery item
groceryInputBtn.addEventListener("click", function(){
nodeConstructor(groceryInput, groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan")});
arr1Output.addEventListener("click", controlBtns);
//add inventory item
inventoryInputBtn.addEventListener("click", function(){
nodeConstructor(inventoryInput, inventoryList, arr2Output, "newInventoryItemDiv",
"newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan")});
arr2Output.addEventListener("click", controlBtns);
//item element builder
function nodeConstructor(inputVal, list, output, divClass,itmClass, deleteClass, moveClass){
const newItmDiv = document.createElement("div");
newItmDiv.classList.add(divClass);
const newItm = document.createElement("span");
newItm.classList.add("itmClass");
const deleteBtnSpan = document.createElement("span");
deleteBtnSpan.innerHTML = "<i class='far fa-trash-alt'></i>";
deleteBtnSpan.classList.add(deleteClass);
const moveBtnSpan = document.createElement("span");
moveBtnSpan.innerHTML = "<i class='fas fa-exchange-alt'></i>";
moveBtnSpan.classList.add(moveClass);
list.push(inputVal.value);
for(let i=0;i<list.length;i++){
newItm.innerText = list[i];
}
newItmDiv.appendChild(newItm);
newItmDiv.appendChild(deleteBtnSpan);
newItmDiv.appendChild(moveBtnSpan);
output.appendChild(newItmDiv);
};
//delete and move buttons
function controlBtns(event){
const clicked = event.target;
for(let i=0;i<groceryList.length;i++){
//grocery delete btn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryDeleteBtnSpan"){
groceryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//grocery move btn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryMoveBtnSpan"){
nodeConstructor(groceryList[i], inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
inventoryList.push(groceryList[i]);
groceryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
}
//inventory delete btn
for(let i=0;i<inventoryList.length;i++){
if(clicked.parentElement.parentElement.innerText==inventoryList[i] &&
clicked.parentElement.classList[0]=="inventoryDeleteBtnSpan"){
inventoryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//inventory move btn
if(clicked.parentElement.parentElement.value==inventoryList[i] &&
clicked.parentElement.classList[0]=="inventoryMoveBtnSpan"){
nodeConstructor(inventoryList[i], groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan");
groceryList.push(inventoryList[i]);
inventoryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
}
console.log("InventoryList: "+inventoryList);
console.log("GroceryList: "+groceryList);
}
Hey so the below code will at least work with the switching, the issue you had is you were not calling the nodeConstructor in the move button and since your lists only contain the value, nothing was being updated.
So what I did was updated nodeConstructor to take both input value and value of the item you are moving with this line const nodeValue = typeof inputVal === 'object' ? inputVal.value : inputVal
Then in the move functions I updated both move functions. I grabbed the old value before I delete it from the list, then I call the nodeContructor so both the lists are updated with the value.
const groceryVal = groceryList[i]
groceryList.splice(i,1);
nodeConstructor(groceryVal, inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
clicked.parentElement.parentElement.remove();
In terms of of what you could be doing. I think you could probably add a click event to the move buttons that update their own position so you dont have to have that big function.
const groceryInput = document.querySelector("#groceryInput");
const groceryInputBtn = document.querySelector("#groceryInputBtn");
const arr1Output = document.querySelector("#arr1Output");
const inventoryInput = document.querySelector("#inventoryInput");
const inventoryInputBtn = document.querySelector("#inventoryInputBtn");
const arr2Output = document.querySelector("#arr2Output");
const groceryList = [];
const inventoryList = [];
let nodeList = [];
groceryInputBtn.addEventListener("click", function(){
nodeConstructor(groceryInput, groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan");
});
arr1Output.addEventListener("click", controlBtns);
inventoryInputBtn.addEventListener("click", function(){
nodeConstructor(inventoryInput, inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
});
arr2Output.addEventListener("click", controlBtns);
function nodeConstructor(inputVal, list, output, divClass,itmClass, deleteClass, moveClass){
const newItmDiv = document.createElement("div");
newItmDiv.classList.add(divClass);
const newItm = document.createElement("span");
newItm.classList.add("itmClass");
const deleteBtnSpan = document.createElement("span");
deleteBtnSpan.innerHTML = "<i class='far fa-trash-alt'></i>";
deleteBtnSpan.classList.add(deleteClass);
const moveBtnSpan = document.createElement("span");
moveBtnSpan.innerHTML = "<i class='fas fa-exchange-alt'></i>";
moveBtnSpan.classList.add(moveClass);
const nodeValue = typeof inputVal === 'object' ? inputVal.value :
inputVal
list.push(nodeValue);
for(let i=0;i<list.length;i++){
newItm.innerText = list[i];
}
newItmDiv.appendChild(newItm);
newItmDiv.appendChild(deleteBtnSpan);
newItmDiv.appendChild(moveBtnSpan);
output.appendChild(newItmDiv);
};
function controlBtns(event){
const clicked = event.target;
for(let i=0;i<groceryList.length;i++){
//groceryDeleteBtn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryDeleteBtnSpan"){
groceryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//groceryMoveBtn
if(clicked.parentElement.parentElement.innerText==groceryList[i] &&
clicked.parentElement.classList[0]=="groceryMoveBtnSpan"){
const groceryVal = groceryList[i]
groceryList.splice(i,1);
nodeConstructor(groceryVal, inventoryList, arr2Output, "newInventoryItemDiv", "newInventoryItem", "inventoryDeleteBtnSpan", "inventoryMoveBtnSpan");
clicked.parentElement.parentElement.remove();
}
}
for(let i=0;i<inventoryList.length;i++){
//inventoryDeleteBtn
if(clicked.parentElement.parentElement.innerText==inventoryList[i] &&
clicked.parentElement.classList[0]=="inventoryDeleteBtnSpan"){
inventoryList.splice(i,1);
clicked.parentElement.parentElement.remove();
}
//inventoryMoveBtn
if(clicked.parentElement.parentElement.innerText==inventoryList[i] && clicked.parentElement.classList[0]=="inventoryMoveBtnSpan"){
const inventoryVal= inventoryList[i]
inventoryList.splice(i,1);
nodeConstructor(inventoryVal, groceryList, arr1Output, "newGroceryItemDiv", "newGroceryItem", "groceryDeleteBtnSpan", "groceryMoveBtnSpan");
clicked.parentElement.parentElement.remove();
}
}
console.log("InventoryList: "+inventoryList);
console.log("GroceryList: "+groceryList);
}
edited with all the code, sorry for my messy coding, I am begginer
hope you can help with this,
I have just created a button in the dom with a function, I gave the button a class to apply an event listener, for some reason i am not able to activate the listener, does anyone have a clue about what I am doing wrong?
//this is th initial array of items, after I am changing it to an arrayof objects
let shoppingList = ['banana','apples','cherries','oranges', 'peaches'];
const list = document.querySelector('.list');
//this is the last thing I need, create new items and allow the del button
const foo=()=>{
console.log('hi');
}
const adder =(item, index, price,name)=>{
list.innerHTML += `<div class='item${[index+1]}'>${name}, price ${price} </div>`;
item[index]= {name,price};
const delElm = document.createElement('button');//the element to remove items
delElm.className = 'remove';
delElm.innerHTML = 'X';
list.appendChild(delElm);
const btndel = document.querySelector('.remove')
console.log(btndel)
btndel.addEventListener('click', foo)
}
//assign a random price to the original array
for (let i = 0; i < shoppingList.length; i++) {
let prices = i+Math.round((((Math.random()*5)+10))*100)/100;
let name = shoppingList[i];
adder(shoppingList,i,prices,name);
}
const btnElm= document.querySelector('.press');
//function to add new elements
const addItm=()=>{
const nameElm = document.querySelector('#text');
const priceElm = document.querySelector('#price');
let name = nameElm.value;
let prices = Number(priceElm.value);
let i = shoppingList.length-1;
adder(shoppingList, i, prices,name)
console.log(shoppingList)
}
console.log(shoppingList)
btnElm.addEventListener('click', addItm)
edit with the HTML, basically, the user can add new items filling the form, each item should be posible to be removed,
<input type="text" id="text" placeholder="name item">
<input type="text" id="price" placeholder="price">
<button class="press">add</button> -->
thanks you in advance
I am trying to create a 'favourites' system where the user can click on a star in the top right of a button to add that course to their list of 'favourites'. Here is the HTML for said button (there are 6 of them and all 6 are the same):
<button class="divflexbuttonitem">
<div class="libraryfaviconcontainer">
<i class="libraryfavicon" onclick="toggleFavourite()"></i>
</div>
</button>
And here is my (attempt at) JavaScript for the toggleFavourite() function:
function toggleFavourite() {
console.log("Running toggleFavourite();");
var favicon = document.getElementsByClassName("libraryfavicon");
var faviconCount = favicon.length;
var favArray = new Array();
var favArrayString = favArray.toString();
var i;
for(i = 0; i < faviconCount; i++) {
favArray.push(favicon[i].id);
}
alert(favArray.length);
alert(favArrayString);
let favourite = false;
if (favicon[i].style.backgroundImage == 'url("libraryfavselected.png")') {
favourite = true;
}
else if (favicon[i].style.backgroundImage == 'url("libraryfavunselected.png")') {
favourite = false;
}
if (!favourite) {
favicon[i].style.backgroundImage = 'url("libraryfavselected.png")';
console.log("Added to Favourites");
}
else {
favicon[i].style.backgroundImage = 'url("libraryfavunselected.png")';
console.log("Removed from Favourites");
}
}
I am trying to get all elements with a specific class name, add them to an array, and call them from an array to change the url of the 'favicon' of the specific favicon that was pressed. However, my code does not work whatsoever and i am lost as to how to correctly code it.
There are better ways to structure this type of application, but here is some really simple code to get you started.
You can see that the fav class is toggled on and off when an item is clicked, and then we can get all the current favourites by querying all elements with the fav class.
const toggleFavourite = (event) => {
if (event.target){
const clickTarget = event.target;
clickTarget.classList.toggle('fav')
}
}
//Example use, get all favs and attach the text as a new element
const getFavs = () => {
const favs = document.querySelectorAll('.fav');
const favContainer = document.querySelector('.favs')
favContainer.innerHTML = "";
for( let fav of favs){
let newFav = document.createElement('div');
newFav.textContent = fav.textContent;
favContainer.appendChild(newFav)
}
}
.fav {
color: red;
}
<i class="" onclick="toggleFavourite(event)">1</i>
<i class="" onclick="toggleFavourite(event)">2</i>
<i class="" onclick="toggleFavourite(event)">3</i>
<i class="" onclick="toggleFavourite(event)">4</i>
<i class="" onclick="toggleFavourite(event)">5</i>
<button id="getFavs" onclick="getFavs()">Get Favs</button>
<section class='favs'>
</section>
Every time I click the "Add to Cart button" it will update the cartarray[]. What I want to do is to add a new object in the cart for every click so that I can have multiple objects for every different Cart item.
(function() {
const cartbtn = document.querySelectorAll(".add_to_cart_button");
cartbtn.forEach(function(btn) {
btn.addEventListener("click", function(event) {
if (event.target.parentElement.classList.contains("add_to_cart_button")) {
let fullpath = event.target.parentElement.previousElementSibling.children[0].children[0].src;
const item = {};
item.img = fullpath;
let name = event.target.parentElement.previousElementSibling.children[3].children[0].textContent;
item.name = name;
let price = event.target.parentElement.previousElementSibling.children[3].children[1].textContent;
let finalprice = price.slice(1).trim();
item.price = finalprice;
const cartarray = [];
var product = function(name, price, img) {
this.name = name
this.price = price
this.img = img
};
cartarray.push(new product(name, finalprice, fullpath));
console.log(cartarray);
}
});
});
})();
<div class="product-item men">
<div class="product discount product_filter">
<div class="product_image">
<img src="images/product_1.png" alt="">
</div>
<div class="favorite favorite_left"></div>
<div class="product_bubble product_bubble_right product_bubble_red d-flex flex-column align-items-center"><span>-$20</span></div>
<div class="product_info">
<h6 id="item-name" class="product_name">Fujifilm X100T 16 MP Digital Camera (Silver)</h6>
<div class="product_price">$520.00</div>
</div>
</div>
<div class="red_button add_to_cart_button">add to cart</div>
</div>
I leave an answer rather than a comment because I still don't have the reputation to leave a comment. Provide the HTML code, as my colleagues said and we'll be able to answer.
Something 'fishy' I notice that may stop your code to work are these two lines of code:
const cartbtn = document.querySelectorAll(".add_to_cart_button");
if (event.target.parentElement.classList.contains("add_to_cart_button"))
It may be the '.' in the first line, or missing in the second line which stops your code working. I may be wrong, it's just an assumption without seeing your full code
cartarray should be declared outside of the addEventListener in order for the items in the cart to be persistent.
I would also suggest to place the creation of the product outside as well, although technically this is not required.
See the following as an example where the for loop is simulating your button clicks:
const cartarray = [];
const product = function(name, price, img) {
return {
name: name,
price: price,
img: img
}
};
for (let x = 1; x < 6; x++) {
cartarray.push(new product('p' + x, x + '.00', 'path/to/img' + x + 'png'));
}
console.log(cartarray);