Reputation: 77
I practicing on an exercise of DOM manipulation (pure vanilla JS) where I need to check all the prices and if any of them is more than £3,00 the whole product card should change its background color into red. For some unknown reasons the code is working perfectly if I'm changing only the price div but, when I'm trying to target the whole card it will change all the cards into red and not only the one with a price of more than £3,00
I don't know what I'm doing wrong. Any help will be appreciated
Here also the link to test the code from the console: : https://www.monoprix.fr/courses/legumes-frais-mpx_c0000400?page=3
Here my snippet:
function exercise_3() {
var price = document.querySelectorAll(".grocery-item__normal-price");
var block = document.querySelectorAll(".grocery-item-item");
let changePriceColor = 300;
block.forEach((card) => {
price.forEach((p) => {
var a = p.innerText.slice(0, 4).replace(/,/g, "");
if (a > changePriceColor) {
card.style.background = "red";
} else {
return "";
}
});
});
}
exercise_3();
<div class="grocery-item-item">
<div class="grocery-item__description-offre">
<a href="/courses/artichaut-blanc--2414383-p">
<div class="grocery-item__description-wrapper">
<div class="grocery-item__dimmer"></div>
<div class="grocery-item__product-card-content discount">
<div class="grocery-item__product-img">
<img
data-tc='["","tc_event_20",""]'
data-tcdata='{"tc_event_11":0,"tc_event_20":{"ecommerceGA":"product_click","productId":2414383,"quantity":0},"tc_event_39":{"action":"cross sell | undefined","position":0}}'
src="https://cdn.monoprix.fr/cdn-cgi/image/width=180,quality=60,format=auto,metadata=none/assets/images/grocery/2414383/580x580.jpg"
width="100"
height="100"
centered="true"
>
</div>
<div class="grocery-item__description">
<div class="grocery-item-brand">
<p></p>
</div>
<div class="grocery-item-range">ARTICHAUT BLANC</div>
<div class="conditioning-description">L'unité</div>
</div>
</div>
</div>
<div class="withPromotionBand-sc-1jbwr08-0 cfLNRM grocery-item__promotions_band">
<div class="promo_map">
<div class="promo_band _red">
<div class="promo_red">-50%</div>
sur le 2ème
</div>
{" "}
</div>
</div>
</a>
</div>
<div class="grocery-item__price-cart">
<div class="grocery-item__price-wrapper">
<div class="grocery-item__price-line-through"></div>
<div class="grocery-item__normal-price">2,00 €</div>
<div class="grocery-item__price-unit">
<p>2,00 € / p</p>
</div>
</div>
<div class="styledAddToCartButton-sc-15efgme-0 fNiyOV">
<div
class="add-to-cart-button__add-button"
id="addToCartButton-2414383"
value="AddToCart"
data-tc='["tc_event_20",""]'
data-tcdata='{"tc_event_20":{"ecommerceGA":"product_add","productId":2414383,"quantity":0},"tc_event_38":{"position":0,"productId":2414383}}'
>
<img
src="/contents/images/cart_icon.svg"
width="40"
height="40"
alt="panier"
class="pannel"
>
</div>
</div>
</div>
</div>
</>
</>;
Upvotes: 0
Views: 74
Reputation: 43880
Note: .forEach()
does not return
anything
You can run flow control statements in one .forEach()
method because typical DOM trees are simple parent/child hierarchies (<table>
s are the exception).
The following function passes 3 parameters:
Number
a real float or integer that is compared to each valueString
a CSS selector of the elements that contains text or has a value property (form controls) of a priceString
a CSS selector of the element that contains priceTagtooExpensive()
const prices = document.querySelectorAll(priceTag);
.forEach()
[...prices].forEach(node => {...
// <div>textContent</div> <!--or--> <input value="value">
let text = node.textContent || node.value;
if (text.length > 0) {...
let price = text.replaceAll(',', '.').split(/[^0-9.]/).join('');
let parent = node.closest(itemCard);
.red
if (parseFloat(price) > limit && parent) {
parent.classList.add('red');
}
const tooExpensive = (limit, priceTag, itemCard) => {
const prices = document.querySelectorAll(priceTag);
[...prices].forEach(node => {
let text = node.textContent || node.value;
if (text.length > 0) {
let price = text.replaceAll(',', '.').split(/[^0-9.]/).join('');
//console.log(price);
let parent = node.closest(itemCard);
if (parseFloat(price) > limit && parent) {
parent.classList.add('red');
}
}
});
};
tooExpensive(3, '.price', '.item');
.item {
width: min-content;
padding: 5px 10px;
margin: 5px 0;
border: 1px black solid;
}
.red {
background: red;
color: white;
}
<fieldset class='item'>
<input class='price' value='$5.00'>
</fieldset>
<div class='item'>
<input class='price' value='2,00'>
</div>
<section class='item'>
<output class='price'>0.6</output>
</section>
<article class='item'>
<p class='price'>8,00</p>
</article>
<div class='item'>
<p class='price'>£3,00</p>
</div>
<aside class='item'>
<div>2999</div>
</aside>
<nav>
<fieldset class='price'>99</fieldset>
</nav>
Upvotes: 0
Reputation: 368
The way you have structured your nested for loops is the causing you to loop over all the prices for each card. Meaning for the 1st card you look at all the prices, inevitably one is higher than 300 so it turns red, then it goes to the next card, looks at all the prices again finds one that is higher than 300 and turns that card red also, it goes on like this until every card has been turned red
function exercise_3() {
var price = document.querySelectorAll(".grocery-item__normal-price");
let changePriceColor = 300;
// So you don't need to run a forloop over the "block",
// instead you could just find the closest '.grocery-item-item'
// to the price that meets your condition, and change its background
price.forEach((p) => {
var a = p.innerText.slice(0, 4).replace(/,/g, "");
if (a > changePriceColor) {
const card = p.closest('.grocery-item-item')
card.style.background = "red";
} else {
return "";
}
});
}
exercise_3();
Upvotes: 1
Reputation: 1932
The problem is, that for all cards you always look at all prices. Instead you should only look at the prices inside the current card. This can be done with card.querySelectorAll, where card
is the current block.
function exercise_3() {
const blocks = document.querySelectorAll(".grocery-item-item");
const changePriceColor = 300;
blocks.forEach((card) => {
const prices = card.querySelectorAll(".grocery-item__normal-price");
prices.forEach((p) => {
const a = p.innerText.slice(0, 4).replace(/,/g, "");
if (a > changePriceColor) {
card.style.background = "red";
} else {
return "";
}
});
});
}
exercise_3();
.grocery-item-item {
border: 1px solid;
}
<div class="grocery-item-item">
<div class="grocery-item__normal-price">2,00 €</div>
<div class="grocery-item__normal-price">2,00 €</div>
</div>
<div class="grocery-item-item">
<div class="grocery-item__normal-price">4,00 €</div>
</div>
<div class="grocery-item-item">
<div class="grocery-item__normal-price">1,00 €</div>
</div>
Upvotes: 2