Create a link on an image and get a popup?

Good morning,

I have my products and I would like to know how to do so that when I click on a product I have a popup that opens to obtain its description.

for (let index = 0; index < products.length; index++) {
    const { id, productName, productPrice, productImg } = products[index]
    itemContainer.innerHTML +=
        ` <div class="card">` +
        ` <article class="cardImg">` +
        ` <img src="./img/${productImg}" alt="">` +
        `</article> ` +
        ` <div class="itemDescContainer">` +
        `<article class="itemDesc">` +
        `<h1 class="itemName">${productName}</h1>` +
        `<p class="itemPrice">${productPrice}€</p>` +
        ` </article> ` +
        `<div class="addtocart" id="addtocart${id}")'>` +
        `<i class="fa-solid fa-cart-shopping cart"></i>` +
        ` </div>` +
        ` </div>` +
        `</div>`
}

css

/* card styles */
.itemContainer {
    width: 95%;
    max-width: 1200px;
    margin: auto;
    margin-top: 2em;
    margin-bottom: 2em;
    display: grid;
    gap: 15px;
    column-gap: 10px;
    row-gap: 30px;
    grid-template-columns: 1fr 1fr;
    justify-items: center;
    align-items: center;

}

.card {
    width: 200px;
    height: 310px;
    padding: .5em;
    background-color: white;
    border-radius: 10px;
    box-shadow: 0 0 15px 3px rgba(0, 0, 0, .1);
    display: flex;
    flex-direction: column;
    align-content: space-between;
}

.totalItem {
    color: #fff;
}

.rightItem {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.totalItem {
    margin-bottom: -9px;
}

.cardImg {
    width: 70%;
    height: 200px;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;
}

.cardImg img {
    width: 100%;
}

.itemDescContainer {
    display: flex;
    justify-content: space-between;
    align-items: end;
    margin-top: 1em;
}

.itemName {
    font-size: 1rem;
    margin-bottom: .3em;
    color: black;
}

.itemPrice {
    font-weight: 500;
    color: black;
}

.addtocart {
    width: 35px;
    height: 35px;
    color: red;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1em;
    border-radius: 50%;
    cursor: pointer;
    transition: all .5s ease-in-out;
}

.addtocart:hover {
    background-color: #dbdbdb;
}

.cart {
    margin: 0;
}

@media screen and (min-width:650px) {
    .itemContainer {
        grid-template-columns: 1fr 1fr 1fr;
    }
}

@media screen and (min-width:900px) {
    .itemContainer {
        grid-template-columns: 1fr 1fr 1fr 1fr;
    }
}

@media screen and (min-width:1100px) {
    .itemContainer {
        grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
    }
}

Thank you for your help.

Is the description already in that code you posted?

I assume that you have the element called “itemDesc” hidden initially and that you want to show it when the image is clicked perhaps?

What sort of popup are you expecting? A tooltip, or a whole page modal or just an expanded section like an accordion?

The basics are that you will add a click event listener to the element you want to trigger the modal and then add a class to the description so that css can show and style it.

If these cards are dynamically generated it may affect the way the js needs to work as you can’t add event listeners to content that hasn’t been added yet so would need to add it to an existing element and let the event bubble up so you can check it.

1 Like

yes indeed I would like that when we go to the image which is in the card we can see in a small window the description of the product.
But I really don’t know how to do this.

the content is in an items.js file

Can you help me ?

export const products = [
    {
        "id": "1",
        "productName": "BoconĂł Specialty Coffee Beans Colombie 1 kg",
        "productPrice": "44.90",
        "productImg": "bocono1_1kg.png"
    },

    {
        "id": "2",
        "productName": "BoconĂł Specialty Coffee Beans Brazil 1 Kg",
        "productPrice": "42.90",
        "productImg": "coffee_brazil_1kg.png"
    },

    {
        "id": "3",
        "productName": "BoconĂł Specialty Coffee Beans Ethiopia 1 Kg",
        "productPrice": "46.90",
        "productImg": "coffee_ethopia_1kg.png"
    },

I assume you have retrieved all the data you need for that card. Or do you need help retrieving that data as that would be a JS question and beyond my scope and I could move the thread to the js forum?.

However, if you have html like this on the page with the fields all already retrieved:

<div class="card">
  <article class="cardImg">
    <img src="https://picsum.photos/id/237/200/300" alt="">
  </article>
  <div class="itemDescContainer">
    <article class="itemDesc">
      <h1 class="itemName">${productName}</h1>
      <p class="itemPrice">${productPrice}€</p>
    </article>
    <div class="addtocart" id="addtocart${id}">
      <i class="fa-solid fa-cart-shopping cart">add to cart
    </div>
  </div>
</div>

Then it would be a matter of showing the itemDescContainer in a popup or similar.

If it was just a reveal panel then you could use the details and summary elements which will hide and show without JS.

e.g.

Its a bit hard to be more specific as there are a lot of ways this could work but depend on what you have got already.

2 Likes

yes you can move it into the js forum

In fact sorry I expressed myself badly I just want that when I click on the image it opens a small modal with the description that I already have in my items.js file

An option is to use a <dialog> element as demonstrated here:

Note: <dialog> is fairly new so will not work with old versions of browser.

3 Likes

Thank you, this is what I would like to do, how to integrate this into my code?

import { products } from "./items";

// Toggle shopping cart
const shoppingCart = document.getElementById("shoppingCart");
const closeCart = document.getElementById("closeCart");

const itemContainer = document.getElementById('itemContainer');
const cartContainer = document.getElementById("cartContainer");
const eachCartItemContainer = document.getElementById("eachCartItemContainer");
const totalItem = document.getElementById("totalItem");

const cartTitle = document.getElementById("cartTitle")
const totalPrice = document.getElementById("totalPrice");
const totalPriceContainer = document.getElementById("totalPriceContainer");

const storedItems = localStorage.getItem("cartItems")
const cartItems = storedItems !== null
    ? storedItems.split(",")
    : []


totalItem.innerText = cartItems.length !== null
    ? cartItems.length - 1
    : 0

// Iterate card
for (let index = 0; index < products.length; index++) {
    const { id, productName, productPrice, productImg } = products[index]
    itemContainer.innerHTML +=
        ` <div class="card">` +
        ` <article class="cardImg">` +
        ` <img src="./img/${productImg}" alt="">` +
        `</article> ` +
        ` <div class="itemDescContainer">` +
        `<article class="itemDesc">` +
        `<h1 class="itemName">${productName}</h1>` +
        `<p class="itemPrice">${productPrice}€</p>` +
        ` </article> ` +
        `<div class="addtocart" id="addtocart${id}")'>` +
        `<i class="fa-solid fa-cart-shopping cart"></i>` +
        ` </div>` +
        ` </div>` +
        `</div>`
}

// Add click event listener for card Item
for (let index = 1; index <= products.length; index++) {
    document.getElementById(`addtocart${index}`).onclick = () => {
        if (cartItems.includes(index) === false) {
            totalItem.innerText = cartItems.length;
            cartItems.unshift(index)
            localStorage.setItem("cartItems", cartItems)
        }
    }
}

shoppingCart.onclick = () => {
    cartContainer.classList.add("showCartContainer");
    displayItemInCart();
}

closeCart.onclick = () => {
    cartContainer.classList.remove("showCartContainer");
}

// AddClickEvent for button
const displayItemInCart = () => {
    cartTitle.innerText = `${cartItems.length - 1} Item In cart`;
    eachCartItemContainer.innerHTML = "";
    if (localStorage.getItem("cartItems")) {
        const cartArray = localStorage.getItem("cartItems").split(",");
        totalPrice.innerText = "";
        totalPriceContainer.style.display = "block"
        products.map((item) => {
            const { id, productName, productPrice, productImg } = item
            if (cartArray.includes(id)) {
                totalPrice.innerHTML = (Number(totalPrice.innerText) + Number(productPrice)).toFixed(2);

                return eachCartItemContainer.innerHTML +=
                    `<div class="eachCart">` +
                    ` <img src="./img/${productImg}" class="cartImg" alt="">` +
                    `<div class="cartDesc">` +
                    `<h1 class="cartItemName">${productName}</h1>` +
                    `<p class="cartItemPrice">${productPrice}€</p>` +
                    `<i class="fa-solid fa-trash fa-lg" id="remove${id}"></i>` +
                    `<i class="fa-solid fa-plus fa-lg" id="addtocart${id}")></i>` +
                    `<i class="fa-solid fa-minus fa-lg" id="addtocart${id}")></i>` +
                    `</div>` +
                    `</div>`
            }
        })
    } else {
        cartTitle.innerText = 'No Item'
        totalPriceContainer.style.display = "none"
    }
    onRemoveButton();

}

const onRemoveButton = () => {
    const itemInCart = localStorage.getItem("cartItems");
    const itemInCartArray = itemInCart.split(",");

    for (let index = 0; index < itemInCartArray.length; index++) {
        const removedItem = itemInCartArray[index]
        document.getElementById(`remove${removedItem}`).onclick = () => {
            const Itemindex = itemInCartArray.indexOf(removedItem)
            cartItems.splice(Itemindex, 1)
            localStorage.setItem("cartItems", cartItems)
            totalItem.innerText = cartItems.length - 1;
            displayItemInCart();
        }
    }
}

css

.card {
    width: 200px;
    height: 310px;
    padding: .5em;
    background-color: white;
    border-radius: 10px;
    box-shadow: 0 0 15px 3px rgba(0, 0, 0, .1);
    display: flex;
    flex-direction: column;
    align-content: space-between;
}

.totalItem {
    color: #fff;
}

.rightItem {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.totalItem {
    margin-bottom: -9px;
}

.cardImg {
    width: 70%;
    height: 200px;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;
}

.cardImg img {
    width: 100%;
}

.itemDescContainer {
    display: flex;
    justify-content: space-between;
    align-items: end;
    margin-top: 1em;
}

.itemName {
    font-size: 1rem;
    margin-bottom: .3em;
    color: black;
}

.itemPrice {
    font-weight: 500;
    color: black;
}

.addtocart {
    width: 35px;
    height: 35px;
    color: red;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1em;
    border-radius: 50%;
    cursor: pointer;
    transition: all .5s ease-in-out;
}

.addtocart:hover {
    background-color: #dbdbdb;
}

.cart {
    margin: 0;
}

@media screen and (min-width:650px) {
    .itemContainer {
        grid-template-columns: 1fr 1fr 1fr;
    }
}

@media screen and (min-width:900px) {
    .itemContainer {
        grid-template-columns: 1fr 1fr 1fr 1fr;
    }
}

@media screen and (min-width:1100px) {
    .itemContainer {
        grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
    }
}

Good morning,

Could you help me adapt this in my code because I can’t integrate it

what was given to me and what I would like to obtain in my code https://codepen.io/Archibald2/pen/NWVyabx

et mon code https://codepen.io/aaashpnt-the-sans/pen/wvbyrRz

Thanks in advance

Good morning,

I tried to do as in your example and it doesn’t work here is my code. your example https://codepen.io/Archibald2/pen/NWVyabx

Can you help me ?

items.js

    {
        "id": "19",
        "productName": "Exclusive coffee gift box - Café Jumbo, 3 sachets of 100 g",
        "productPrice": "34.90",
        "productImg": "coffee_19_lot.png"
    },

    {
        "id": "20",
        "productName": "Coffee gift box | 5x 100g coffee bean",
        "productPrice": "44.90",
        "productImg": "coffee_coffret_500g_grain.png"
    }

];


const dlg = document.querySelector("article");

function clicked() {
    document.getElementById("name").innerText = products[this.id].productName;
    document.getElementById("price").innerText = products[this.id].productPrice + "€";
    dlg.showModal();
}

document.querySelector("button").addEventListener("click", () => { dlg.close() });

const cardImg = document.querySelectorAll(".cardImg");
cardImg.forEach(e => e.addEventListener("click", clicked));

script.js

// Iterate card
for (let index = 0; index < products.length; index++) {
    const { id, productName, productPrice, productImg } = products[index]
    itemContainer.innerHTML +=
        ` <div class="card">` +
        ` <article class="cardImg">` +
        ` <img src="./img/${productImg}" alt="">` +
        `</article> ` +
        ` <div class="itemDescContainer">` +
        `<article class="itemDesc">` +
        `<h1 class="itemName">${productName}</h1>` +
        `<p class="itemPrice">${productPrice}€</p>` +
        ` </article> ` +
        `<div class="addtocart" id="addtocart${id}")'>` +
        `<i class="fa-solid fa-cart-shopping cart"></i>` +
        ` </div>` +
        ` </div>` +
        `</div>` +
         `<article>`
            ` <button>X</button>`
            ` <p id="name"></p>`
            ` <p id="price"></p>`
            `</article>`
}

Style.css

.cardImg {
    width: 70%;
    height: 200px;
    margin: auto;
    display: flex;
    justify-content: center;
    align-items: center;
}

.cardImg img {
    width: 100%;
}

.cardImg::backdrop {
    background: rgba(0, 0, 0, 0.7);
}

It looks to me as though you have already output that information into each card already?

You could then as I mentioned before just hide it in the card with css and then show it mid screen when clicked.

This following code is a mess as I just cobbled bits together to get to working but maybe it will help towards a solution. (There are errors in the console but that’s not from the code I added).

Maybe someone more experienced than me can tidy it up for you if its doing what you want. :slight_smile:

Thank you for your help I will test it.

Maybe I should follow a tutorial and create my online store at the same time, I looked a little on the internet and there are a lot of tutorials but I’m looking for a tutorial for a mini online store since I don’t I only have 7 items.

Do you know a good tutorial? (online store with integrated payment system).