Editing And Deleting Products

shopping bag logo

Selecting the save-edit button

We now have a modal that displays the selected product title and price. The modal also has a button to save these changes:

<!-- dashboard.html -->
<div class="modal-content">
    <label for="edit-name">Name:</label>
    <input id="edit-name" type="text" />
    <label for="edit-price">Price:</label>
    <input id="edit-price" type="number" step=".01" />
    <div class="modal-buttons">
        <!-- save changes button -->
        <button id="save-edit">Save</button>
        <button id="cancel-edit">Cancel</button>
    </div>
</div>

Back to the script.js we can select this button, listen for a click, and call a function to edit the product. Add the following to the end of the script:

document.getElementById("save-edit")?.addEventListener("click", editProduct);

function editProduct() {

}

Editing the product

Use this function to select the name and price input elements:

function editProduct() {
    const nameInput = document.getElementById("edit-name");
    const priceInput = document.getElementById("edit-price");
}

Not only do these input elements contain the current product information, we can also type into them to update. Use the value of these inputs to set the product from the filteredProducts array:

function editProduct() {
    const nameInput = document.getElementById("edit-name");
    const priceInput = document.getElementById("edit-price");

    if (currentEditIndex !== null) {
        filteredProducts[currentEditIndex].name = nameInput.value;
        filteredProducts[currentEditIndex].price = priceInput.value;
    }

    closeEditModal();
    renderProducts();
}
  • if (currentEditIndex !== null): When the modal is opened we store the index position of the selected product, this if statement will first check we have a value before proceeding.
  • filteredProducts[currentEditIndex].name = nameInput.value: This index position is used to select the current product from the array, and we update the name property to be the updated value. This is repeated for the price.
  • The final stage is to close the modal and re-render the products with the update.

The products should now update in the browser after an update. Remember, since we are fetching products from and API, a new set of products will be created after a page refresh. To permanently store products we would need to expand the project to use a database.

Deleting the product

To delete the product we listen for a click on the Delete button inside of the renderTableRows function:

function renderTableRows(container, products) {
    products.forEach(function (product, index) {
        const row = document.createElement("tr");
        row.innerHTML = `
            <td>${product.name}</td>
            <td>$${product.price}</td>
            <td>
                <button class="edit-btn" onclick="openEditModal(${index})">Edit</button>
                // add onclick attribute:
                <button class="delete-btn" onclick="deleteProduct(${index})">Delete</button>
            </td>
        `;
        container.appendChild(row);
    });
}

This also uses the index position to find the selected product. Create the deleteProduct() function in the script:

function deleteProduct(index) {
    filteredProducts.splice(index, 1);
    renderProducts();
    createPaginationButtons();
}

This uses the splice array method to remove an array item. The first parameter is the starting position, which is the index position. The second parameter of 1 means we only want to remove one value.

The products are then re-rendered with the product removed, and the pagination buttons are re-generated to account for less products.

Final script.js code

let products = [];
let filteredProducts = [];

const API_URL = "https://fakerapi.it/api/v2/products?_quantity=20";
let currentPage = 1;
const ITEMS_PER_PAGE = 5;
let currentEditIndex = null;
async function fetchProducts() {
    const response = await fetch(API_URL);
    const data = await response.json();
    products = data.data;
    filteredProducts = products;
    createPaginationButtons();
    renderProducts();
}
fetchProducts();

function renderProducts() {
    const productList = document.getElementById("product-list");
    const productTable = document.getElementById("product-table");

    const start = (currentPage - 1) * ITEMS_PER_PAGE;
    const end = start + ITEMS_PER_PAGE;
    const currentProducts = filteredProducts.slice(start, end);

    if (window.location.pathname.includes("dashboard.html")) {
        productTable.innerHTML = "";
        renderTableRows(productTable, currentProducts);
    } else {
        productList.innerHTML = "";
        renderProductCards(productList, currentProducts);
    }
}

function renderProductCards(container, products) {
    products.forEach(function (product) {
        const card = document.createElement("article");
        card.setAttribute("class", "product-card");
        card.innerHTML = `<section class="product-image">
      <img
        src="images/t-shirt-blue.png"
        alt="blue t-shirt with short sleeves"
        class="product-image"
      />
    </section>
    <section class="product-details">
        <h3>${product.name}</h3>
        <p>${product.description}</p>
        <p class="price">$${product.price}</p>
    </section>`;

        container.appendChild(card);
    });
}

function renderTableRows(container, products) {
    products.forEach(function (product, index) {
        const row = document.createElement("tr");
        row.innerHTML = `
            <td>${product.name}</td>
            <td>$${product.price}</td>
            <td>
                <button class="edit-btn" onclick="openEditModal(${index})">Edit</button>
                <button class="delete-btn" onclick="deleteProduct(${index})">Delete</button>
            </td>
        `;
        container.appendChild(row);
    });
}

function createPaginationButtons() {
    const totalPages = Math.ceil(filteredProducts.length / ITEMS_PER_PAGE);
    const pagination = document.getElementById("pagination");
    pagination.innerHTML = "";
    for (let i = 1; i <= totalPages; i++) {
        const button = document.createElement("button");
        button.textContent = i;
        if (i === currentPage) {
            button.classList.add("active");
        }

        button.addEventListener("click", function () {
            currentPage = i;
            renderProducts();
            createPaginationButtons();
        });

        pagination.appendChild(button);
    }
}

document.getElementById("search")?.addEventListener("input", function (e) {
    const searchTerm = e.target.value.toLowerCase();

    filteredProducts = products.filter(function (product) {
        return product.name.toLowerCase().includes(searchTerm);
    });
    renderProducts();
    createPaginationButtons();
});

function openEditModal(index) {
    const modal = document.getElementById("edit-modal");
    const nameInput = document.getElementById("edit-name");
    const priceInput = document.getElementById("edit-price");

    currentEditIndex = index;
    nameInput.value = filteredProducts[index].name;
    priceInput.value = filteredProducts[index].price;

    modal.style.display = "flex";
}

function closeEditModal() {
    const modal = document.getElementById("edit-modal");
    modal.style.display = "none";
}

document
    .getElementById("cancel-edit")
    ?.addEventListener("click", closeEditModal);

document.getElementById("save-edit")?.addEventListener("click", editProduct);

function editProduct() {
    const nameInput = document.getElementById("edit-name");
    const priceInput = document.getElementById("edit-price");

    if (currentEditIndex !== null) {
        filteredProducts[currentEditIndex].name = nameInput.value;
        filteredProducts[currentEditIndex].price = priceInput.value;
    }

    closeEditModal();
    renderProducts();
}

function deleteProduct(index) {
    filteredProducts.splice(index, 1);
    renderProducts();
    createPaginationButtons();
}

Congratulations!

We hope you have enjoyed this practical course and gained some valuable skills. You have now completed the course!

fireworks image