0

I am creating an E-Commerce website. Within this E-Commerce website, I have a products page. This products page contains multiple types of products.

I have created seperate buttons that the user can click on to show different products. For example, when the user clicks on the button titled 'Xbox', only products with the platform 'xbox' should show up. The color of the button titled 'Xbox' should also turn red, and any other buttons should turn white.

I have written the following code:

        <div id="buttons">
            <button class="button-value" onclick="filterProduct('all')">All</button>
            <button class="button-value" onclick="filterProduct('xbox')">Xbox</button>
            <button class="button-value" onclick="filterProduct('playstation-5')">PlayStation 5</button>
        </div>
        <div id="products"></div>
#buttons {
    text-align: center;
}

.button-value {
    border: 2px solid #ff0000;
    padding: 1em 2.2em;
    border-radius: 3em;
    background-color: transparent;
    color: #ff0000;
    cursor: pointer;
}

.active {
    background-color: #ff3333;
    color: #ffffff;
}
let products = {
    data: [
        {
            productName: "Alan Wake Remasterd",
            developer: "Epic Games",
            genre: "",
            pegi: "16",
            platforms: ["Xbox Series X"],
            price: "24.99",
            image: "images/images/xbox/alan-wake-remastered-xbox.jpg",
        },
        {
            productName: "Battlefield 2042",
            developer: "Electronic Arts",
            genre: "",
            pegi: "16",
            platforms: ["Xbox Series X", "PlayStation 5"],
            price: "24.99",
            image: "images/images/xbox/battlefield-2042-xbox.jpg",
        },
    ],
};

for (let i of products.data) {
    // Create Card
    let card = document.createElement("div");
    // Card should have a category and should stay hidden initialy
    card.classList.add("card", i.category, "hide");
    // image div
    let imgContainer = document.createElement("div");
    imgContainer.classList.add("image-container");
    // img tag
    let image = document.createElement("img");
    image.setAttribute("src", i.image);
    imgContainer.appendChild(image);
    card.appendChild(imgContainer);
    // Container
    let container = document.createElement("div");
    container.classList.add("container");
    // Product Name
    let name = document.createElement("h5");
    name.classList.add("product-name");
    name.innerText = i.productName.toUpperCase();
    container.appendChild(name);
    // Product Price
    let price = document.createElement("h6");
    price.innerText = "$" + i.price;
    container.appendChild(price);

    card.appendChild(container);
    document.getElementById("products").appendChild(card);
}

// Parameter passed from button (Parameter same as category)
function filterProduct(value) {
    // Button Class Code
    let buttons = document.querySelectorAll(".button-value");
    buttons.forEach((button) => {
        // Check if value equals innerText
        if (value.toUpperCase() == button.innerText.toUpperCase()) {
            button.classList.add("active");
        } else {
            button.classList.remove("active");
        }
    });

    // Select all elements
    let elements = document.querySelectorAll(".card");
    // Loop through the elements
    elements.forEach((element) => {
    // Display all cards on all button click
    if (value == "all") {
        element.classList.remove("hide");
    } else {
        // Check if element contains category class
        if (element.classList.contains(value)) {
            // Display elements based on category
            element.classList.remove("hide");
        } else {
            // Hide other elements
            element.classList.add("hide");
        }
    }
});
}



function filterProduct(value) {
    // Button Class Code
    let buttons = document.querySelectorAll(".button-value");
    buttons.forEach((button) => {
        // Check if value equals innerText
        if (value.toUpperCase() == button.innerText.toUpperCase()) {
            button.classList.add("active");
        } else {
            button.classList.remove("active");
        }
    });

This code produces the following output: Output of my HTML, CSS and JavaScript code

However, when I click on the button titled 'Xbox', the color of the button changes, but no cards are displayed. When I click on the button titled 'Playstation 5', the color of the button does not change and the cards are not displayed.

I want the color of the 'Playstation 5' button to also display, and for all of the cards which need to be displayed, to display.

  • 1
    This is a good opportunity for you to start familiarizing yourself with [using a debugger](https://stackoverflow.com/q/25385173/328193). When you step through the code in a debugger, which operation first produces an unexpected result? What were the values used in that operation? What was the result? What result was expected? Why? To learn more about this community and how we can help you, please start with the [tour] and read [ask] and its linked resources. – David Jan 18 '23 at 18:39
  • You have 2 filterProduct() functions. You don't have a "category" entry in your JS objects but you're trying to add it in this line: card.classList.add("card", i.category, "hide"); – metatron Jan 18 '23 at 19:39

1 Answers1

0
//I didn't want to create a CSS/HTML file..
(()=>{
    let style = document.createElement("style");
    style.textContent = `
    #buttons {
        text-align: center;
    }
    
    .button-value {
        border: 2px solid #ff0000;
        padding: 1em 2.2em;
        border-radius: 3em;
        background-color: transparent;
        color: #ff0000;
        cursor: pointer;
    }
    
    .active {
        background-color: #ff3333;
        color: #ffffff;
    }
    
    .hide {
        display: none;
    }
    `;
    document.head.appendChild(style);

    let cc = document.createElement("div");
    cc.id = "products";
    document.body.appendChild(cc);

    let btns = document.createElement("div");
    btns.id = "buttons";
    document.body.appendChild(btns);
})();

let products = {
    data: [
        {
            productName: "Alan Wake Remasterd",
            developer: "Epic Games",
            genre: "",
            pegi: "16",
            platforms: ["Xbox Series X"],
            price: "24.99",
            image: "images/images/xbox/alan-wake-remastered-xbox.jpg",
        },
        {
            productName: "Battlefield 2042",
            developer: "Electronic Arts",
            genre: "",
            pegi: "16",
            platforms: ["Xbox Series X", "PlayStation 5"],
            price: "24.99",
            image: "images/images/xbox/battlefield-2042-xbox.jpg",
        },
    ],
};

//no spaces allowed in class names, filter them out with _
function platformToClassName (platform) {
    return platform.replaceAll(" ", "_");
}

//get the products container
let cardContainer = document.getElementById("products");

//get the filter buttons container
let filterButtonsContainer = document.getElementById("buttons");

//create a filter button given its textContent
function createFilterButton (platform) {
    let platformButton = document.createElement("button");
    platformButton.textContent = platform;
    platformButton.classList.add("button-value");

    platformButton.addEventListener("click", (evt)=>{
        filterProduct(platformButton.textContent);
    });
    filterButtonsContainer.appendChild(platformButton);
}

//create a card in UI
function createProductCard (product) {
    // Create Card
    let card = document.createElement("div");
    // Card should have a category and should stay hidden initialy
    card.classList.add("card", "hide");

    for (let platform of product.platforms) {
        let platformClassName = platformToClassName(platform);
        card.classList.add(platformClassName);
    }
    
    cardContainer.appendChild(card);

    // image div
    let imgContainer = document.createElement("div");
    imgContainer.classList.add("image-container");
    card.appendChild(imgContainer);

    // img tag
    let image = document.createElement("img");
    image.setAttribute("src", product.image);
    imgContainer.appendChild(image);
    
    // Container
    let container = document.createElement("div");
    container.classList.add("container");
    card.appendChild(container);
    
    // Product Name
    let name = document.createElement("h5");
    name.classList.add("product-name");
    name.innerText = product.productName.toUpperCase();
    container.appendChild(name);
    
    // Product Price
    let price = document.createElement("h6");
    price.innerText = "$" + product.price;
    container.appendChild(price);
}

//create a display of products given their object data
function populateProducts (products) {
    let platforms = new Set(); //collection of platforms given the data from products

    for (let i of products.data) {
        //collect the platforms from the product
        for (let platform of i.platforms) {
            platforms.add(platform);
        }
        console.log(i);
        createProductCard(i);
    }

    //create buttons
    createFilterButton("all");

    for (let platform of platforms) {
        createFilterButton(platform);
    }
}

//actually do the operation
populateProducts(products);

// Parameter passed from button (Parameter same as category)
function filterProduct(value) {

    // Select buttons
    let buttons = document.querySelectorAll(".button-value");
    // Loop through them
    for (let button of buttons) {
        
        // Check if value equals innerText
        let VALUE = value.toUpperCase();
        let BUTTON_TEXT = button.textContent.toUpperCase();
        console.log(VALUE, BUTTON_TEXT);

        if (VALUE == BUTTON_TEXT) {
            button.classList.add("active");
        } else {
            button.classList.remove("active");
        }
    }

    //class names can't have spaces, convert it
    value = platformToClassName(value);

    // Select card elements
    let elements = document.querySelectorAll(".card");
    // Loop through them
    for (let element of elements) {
        
        // update which cards are shown based on what filtered value is
        if (value == "all" || element.classList.contains(value)) {
            element.classList.remove("hide");
        } else {
            element.classList.add("hide");
        }

    }
}

This is paste-able into the console if you want to try it out..

Jon
  • 136
  • 3
  • 12