Xây dựng Tính năng Hiển thị Sản phẩm và Giỏ hàng với ASP.NET MVC

Việc hiển thị danh sách sản phẩm và quản lý giỏ hàng là các chức năng cơ bản trong nhiều ứng dụng web thương mại điện tử. Bài viết này trình bày cách triển khai các tính năng này sử dụng mô hình ASP.NET MVC, JavaScript (jQuery) và CSS.

Cấu trúc Giao diện Người dùng (HTML/Razor)

Giao diện người dùng được xây dựng bằng Razor View Engine trong ASP.NET MVC. Trang chính bao gồm phần tiêu đề, khu vực hiển thị sản phẩm, phân trang và một thanh menu bên phải chứa thông tin người dùng và giỏ hàng.


@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Thực đơn Nhà hàng</title>
    <link rel="icon" href="~/Content/Images/Icon/Logo.png" />
    <link href="~/Plugin/layui/css/layui.css" rel="stylesheet" />
    <link href="~/Content/Css/MenuDisplay.css" rel="stylesheet" />
</head>
<body>
    <div style="width:100%;height:80px;"></div>
    <header>
        <div class="header-left">
            <span><img src="~/Content/Images/Icon/Logo.png" alt="Logo" /></span>
            <h1>Nhà hàng Hạnh Phúc</h1>
        </div>
        <div class="header-right">
            <p>Chưa đăng nhập, <a onclick="window.location.href='/Account/Login'">Đăng nhập</a></p>
        </div>
    </header>
    <div class="navigation"><p>Thực đơn</p></div>
    <div class="product-grid">
        <!-- Sản phẩm sẽ được tải động vào đây -->
    </div>
    <div class="pagination">
        <button class="prev-page">Trang trước</button>
        <div class="page-numbers">
            <button class="page-num active" data-page="1">1</button>
        </div>
        <button class="next-page">Trang sau</button>
    </div>
    <div class="side-menu">
        <ul class="menu-list">
            <li class="menu-item"><i class="icon-info" title="Thông tin cá nhân"></i></li>
            <li class="menu-item cart-toggle"><i class="icon-cart" title="Giỏ hàng"></i>
            <ul class="cart-dropdown" hidden>
                <li  class="cart-items-container">
                    <ul class="cart-items">
                        <!-- Các món hàng trong giỏ sẽ được tải động vào đây -->
                    </ul>
                </li>
                <li class="checkout-area"><button>Thanh toán</button></li>
            </ul>
            </li>
        </ul>
    </div>
    <b id="loggedInUsername" hidden>@Session["UserName"]</b>
    <b id="loggedInUserId" hidden>@Session["UserID"]</b>

    <script src="~/Plugin/jquery-3.3.1.min.js"></script>
    <script src="~/Plugin/layui/layui.all.js"></script>
    <script>
        const loggedInUsernameElement = $("#loggedInUsername");
        const loggedInUserIdElement = $("#loggedInUserId");
        const headerRightParagraph = $("header .header-right p");
        const productGrid = $(".product-grid");
        const cartItemsList = $(".cart-items");
        
        let allProductsData = [];
        const itemsPerPage = 12; // Số lượng sản phẩm hiển thị mỗi trang
        let currentPage = 1;

        // Cập nhật trạng thái đăng nhập
        if (loggedInUsernameElement.html() !== "") {
            headerRightParagraph.html("Chào mừng, " + loggedInUsernameElement.html());
        }

        // Tải danh sách sản phẩm
        function loadProducts(page = 1) {
            $.ajax({
                type: "GET",
                url: "/Shop/GetProducts",
                dataType: "json",
                success: function (products) {
                    allProductsData = products; // Lưu toàn bộ dữ liệu để phân trang phía client nếu cần
                    renderProducts(allProductsData, page);
                    renderPagination(allProductsData.length);
                },
                error: function (xhr, status, error) {
                    console.error("Lỗi khi tải sản phẩm: " + error);
                }
            });
        }

        function renderProducts(products, page) {
            productGrid.empty();
            const startIndex = (page - 1) * itemsPerPage;
            const endIndex = startIndex + itemsPerPage;
            const productsToShow = products.slice(startIndex, endIndex);

            let productHtml = "<table><tbody><tr>";
            $.each(productsToShow, function (i, product) {
                productHtml += `
                    <td>
                        <div class="product-info-overlay">
                            <div>
                                <h2>${product.Name}</h2>
                                <p>&#x00A5;<span>${product.Price}</span></p>
                                <i class="add-to-cart-btn" data-product-id="${product.ID}"></i>
                                <i class="view-details-btn"></i>
                            </div>
                        </div>
                        <img src="${product.ImageUrl}" alt="${product.Name}" />
                    </td>
                `;
            });
            productHtml += "</tr></tbody></table>";
            productGrid.append(productHtml);
            
            // Gán sự kiện cho nút "Thêm vào giỏ"
            $(".add-to-cart-btn").on("click", function() {
                const productId = $(this).data("product-id");
                addToCart(productId);
            });
        }

        function renderPagination(totalItems) {
            const totalPages = Math.ceil(totalItems / itemsPerPage);
            const pageNumbersDiv = $(".page-numbers");
            pageNumbersDiv.empty();

            for (let i = 1; i <= totalPages; i++) {
                const pageButton = $(`<button class="page-num" data-page="${i}">${i}</button>`);
                if (i === currentPage) {
                    pageButton.addClass("active");
                }
                pageNumbersDiv.append(pageButton);
            }

            // Gán sự kiện cho các nút phân trang
            $(".page-num").off("click").on("click", function() {
                currentPage = parseInt($(this).data("page"));
                renderProducts(allProductsData, currentPage);
                $(".page-num").removeClass("active");
                $(this).addClass("active");
            });

            $(".prev-page").off("click").on("click", function() {
                if (currentPage > 1) {
                    currentPage--;
                    renderProducts(allProductsData, currentPage);
                    $(".page-num").removeClass("active").filter(`[data-page="${currentPage}"]`).addClass("active");
                }
            });

            $(".next-page").off("click").on("click", function() {
                if (currentPage < totalPages) {
                    currentPage++;
                    renderProducts(allProductsData, currentPage);
                    $(".page-num").removeClass("active").filter(`[data-page="${currentPage}"]`).addClass("active");
                }
            });
        }

        // Mở hoặc đóng giỏ hàng
        $(".cart-toggle").on("click", function(e) {
            const cartDropdown = $(".cart-dropdown");
            cartDropdown.attr("hidden", !cartDropdown.attr("hidden"));
            if (!cartDropdown.attr("hidden")) {
                loadCartItems();
            }
            e.stopPropagation(); // Ngăn chặn sự kiện click lan truyền
        });

        $(".cart-dropdown").on("click", function(e) {
            e.stopPropagation(); // Ngăn chặn sự kiện đóng giỏ hàng khi click vào bên trong
        });

        // Tải các món hàng trong giỏ
        function loadCartItems() {
            if (loggedInUserIdElement.html() !== "") {
                cartItemsList.empty(); // Xóa các mục hiện có trước khi tải lại
                $.ajax({
                    type: "GET",
                    url: "/Shop/GetCartItems",
                    dataType: "json",
                    data: { userId: loggedInUserIdElement.html() },
                    success: function (cartData) {
                        $.each(cartData, function (i, item) {
                            cartItemsList.append(`
                                <li class="cart-item-entry" data-cart-id="${item.CartID}">
                                    <img src="${item.Product.ImageUrl}" alt="${item.Product.Name}" />
                                    <p><label>${item.Product.Name}</label>&#x00A5;<span class="item-price">${item.Product.Price}</span></p>
                                    <div class="quantity-control">
                                        <button class="quantity-minus">-</button>
                                        <input type="number" min="1" max="999" value="${item.Quantity}" class="quantity-input">
                                        <button class="quantity-plus">+</button>
                                    </div>
                                    <i class="remove-from-cart-btn" title="Xóa">X</i>
                                </li>
                            `);
                        });
                        initQuantityControl(); // Khởi tạo điều khiển số lượng
                        updateCartTotal(); // Cập nhật tổng tiền giỏ hàng
                    },
                    error: function (xhr, status, error) {
                        console.error("Lỗi khi tải giỏ hàng: " + error);
                    }
                });
            } else {
                alert("Vui lòng đăng nhập để xem giỏ hàng!");
                window.location.href = "/Account/Login";
            }
        }

        // Thêm sản phẩm vào giỏ hàng
        function addToCart(productId) {
            if (loggedInUserIdElement.html() !== "") {
                $.ajax({
                    type: "POST", // Sử dụng POST cho các hành động thay đổi dữ liệu
                    dataType: "json",
                    url: "/Shop/AddProductToCart",
                    data: { userId: loggedInUserIdElement.html(), productId: productId, quantity: 1 }, // Mặc định thêm 1 sản phẩm
                    success: function (response) {
                        alert(response.Message);
                        if (response.Success) {
                            // Cập nhật giỏ hàng nếu nó đang mở
                            if (!$(".cart-dropdown").attr("hidden")) {
                                loadCartItems();
                            }
                        }
                    },
                    error: function (xhr, status, error) {
                        alert("Có lỗi xảy ra khi thêm sản phẩm vào giỏ.");
                        console.error("Lỗi khi thêm vào giỏ hàng: " + error);
                    }
                });
            } else {
                alert("Vui lòng đăng nhập để thêm sản phẩm vào giỏ!");
                window.location.href = "/Account/Login";
            }
        }

        // Khởi tạo điều khiển số lượng và các sự kiện liên quan
        function initQuantityControl() {
            $(".quantity-minus").off("click").on("click", function() {
                const input = $(this).next(".quantity-input");
                let currentValue = parseInt(input.val());
                if (currentValue > parseInt(input.attr("min"))) {
                    input.val(currentValue - 1);
                    // Cập nhật số lượng trên server
                    updateCartItemQuantity(input);
                    updateCartTotal();
                }
            });

            $(".quantity-plus").off("click").on("click", function() {
                const input = $(this).prev(".quantity-input");
                let currentValue = parseInt(input.val());
                if (currentValue < parseInt(input.attr("max"))) {
                    input.val(currentValue + 1);
                    // Cập nhật số lượng trên server
                    updateCartItemQuantity(input);
                    updateCartTotal();
                }
            });

            $(".quantity-input").off("change").on("change", function() {
                // Đảm bảo giá trị nằm trong giới hạn min/max
                let currentValue = parseInt($(this).val());
                if (isNaN(currentValue) || currentValue < parseInt($(this).attr("min"))) {
                    $(this).val(parseInt($(this).attr("min")));
                } else if (currentValue > parseInt($(this).attr("max"))) {
                    $(this).val(parseInt($(this).attr("max")));
                }
                // Cập nhật số lượng trên server
                updateCartItemQuantity($(this));
                updateCartTotal();
            });

            $(".remove-from-cart-btn").off("click").on("click", function() {
                const cartItemElement = $(this).closest(".cart-item-entry");
                const cartItemId = cartItemElement.data("cart-id");
                if (confirm("Bạn có chắc muốn xóa mục này khỏi giỏ hàng?")) {
                    removeCartItem(cartItemId, cartItemElement);
                }
            });
        }
        
        // Cập nhật số lượng sản phẩm trong giỏ hàng trên server
        function updateCartItemQuantity(quantityInput) {
            const cartItemElement = quantityInput.closest(".cart-item-entry");
            const cartItemId = cartItemElement.data("cart-id");
            const newQuantity = parseInt(quantityInput.val());

            if (loggedInUserIdElement.html() !== "" && cartItemId) {
                $.ajax({
                    type: "POST",
                    url: "/Shop/UpdateCartItemQuantity",
                    dataType: "json",
                    data: { cartItemId: cartItemId, newQuantity: newQuantity },
                    success: function (response) {
                        if (!response.Success) {
                            alert("Cập nhật số lượng thất bại: " + response.Message);
                            // Có thể hoàn tác giá trị input nếu cập nhật lỗi
                            loadCartItems(); 
                        }
                    },
                    error: function (xhr, status, error) {
                        alert("Có lỗi xảy ra khi cập nhật số lượng.");
                        console.error("Lỗi khi cập nhật giỏ hàng: " + error);
                    }
                });
            }
        }

        // Xóa sản phẩm khỏi giỏ hàng
        function removeCartItem(cartItemId, cartItemElement) {
             if (loggedInUserIdElement.html() !== "" && cartItemId) {
                $.ajax({
                    type: "POST",
                    url: "/Shop/RemoveCartItem",
                    dataType: "json",
                    data: { cartItemId: cartItemId },
                    success: function (response) {
                        if (response.Success) {
                            cartItemElement.remove(); // Xóa khỏi DOM
                            updateCartTotal(); // Cập nhật tổng tiền
                        } else {
                            alert("Xóa sản phẩm thất bại: " + response.Message);
                        }
                    },
                    error: function (xhr, status, error) {
                        alert("Có lỗi xảy ra khi xóa sản phẩm.");
                        console.error("Lỗi khi xóa khỏi giỏ hàng: " + error);
                    }
                });
            }
        }

        // Cập nhật tổng tiền giỏ hàng
        function updateCartTotal() {
            let totalAmount = 0;
            $(".cart-item-entry").each(function () {
                const price = parseFloat($(this).find(".item-price").text());
                const quantity = parseInt($(this).find(".quantity-input").val());
                if (!isNaN(price) && !isNaN(quantity)) {
                    totalAmount += price * quantity;
                }
            });
            $(".checkout-area button").text(`Thanh toán ¥${totalAmount.toFixed(2)}`);
        }

        // Khởi tạo khi tài liệu đã sẵn sàng
        $(document).ready(function() {
            loadProducts();
        });
    </script>
</body>
</html>

Tạo kiểu với CSS

Tệp CSS (MenuDisplay.css) định nghĩa các kiểu cho bố cục trang, hiển thị sản phẩm, thanh phân trang và menu bên phải. Các tên lớp được thay đổi để rõ ràng hơn.


body {
    padding: 0;
    margin: 0;
    font-family: Arial, sans-serif;
    background: #f8f8f8;
    color: #333;
}

::-webkit-scrollbar {
    background: rgba(0, 0, 0,.1);
    height: 10px;
    width: 10px;
}

::-webkit-scrollbar-thumb {
    background: #dbb900;
    border-radius: 50px;
}

header {
    box-shadow: 0px 1px 15px 0px rgba(0, 0, 0,.1);
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: fixed;
    top: 0px;
    left: 0px;
    width: 100%;
    background: #fff;
    z-index: 10;
    height: 70px; /* Điều chỉnh chiều cao header */
}

    header:after {
        content: '';
        position: absolute;
        left: 0;
        bottom: 0;
        background: #67b968;
        width: 100%;
        height: 3px;
    }

.header-left {
    display: flex;
    align-items: center;
    padding-left: 20px;
}

    .header-left h1 {
        margin: 0;
        padding-left: 15px;
        font-size: 24px;
        color: #333;
    }

    .header-left img {
        height: 40px;
        width: 40px;
    }

.header-right {
    padding-right: 20px;
}

    .header-right p {
        margin: 0;
    }

        .header-right p a {
            color: #67b968;
            text-decoration: none;
        }

            .header-right p a:hover {
                text-decoration: underline;
                cursor: pointer;
            }

.navigation {
    padding: 10px 20px;
    box-sizing: border-box;
    background: rgba(0,0,0,.03);
    color: #67b968;
    font-size: 18px;
    margin-top: 70px; /* Offset for fixed header */
}

.product-grid {
    width: calc(100% - 50px); /* Kích thước trừ menu phải */
    min-height: calc(100vh - 70px - 45px - 60px - 20px); /* trừ header, nav, pagination, padding */
    overflow: auto;
    padding: 20px;
    box-sizing: border-box;
    background: rgba(0,0,0,0.02);
    float: left;
}

    .product-grid table {
        width: 100%;
        border-collapse: collapse;
    }

        .product-grid table tr {
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
            justify-content: flex-start;
            gap: 20px; /* Khoảng cách giữa các sản phẩm */
        }

        .product-grid table tbody tr td {
            text-align: center;
            position: relative;
            width: 250px; /* Chiều rộng cố định cho mỗi sản phẩm */
            height: 200px;
            margin-bottom: 20px;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: 0 4px 10px rgba(0,0,0,0.05);
            transition: transform 0.2s ease-in-out;
            cursor: pointer;
        }

            .product-grid table tbody tr td:hover {
                transform: translateY(-5px);
            }

            .product-grid table tbody tr td img {
                width: 100%;
                height: 100%;
                object-fit: cover;
                border-radius: 8px;
            }

            .product-grid table tbody tr td .product-info-overlay {
                position: absolute;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0,0,0,0.6);
                color: #fff;
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
                opacity: 0;
                transition: opacity 0.3s ease-in-out;
                border-radius: 8px;
            }

                .product-grid table tbody tr td .product-info-overlay:hover {
                    opacity: 1;
                }

                .product-grid table tbody tr td .product-info-overlay h2 {
                    font-size: 20px;
                    margin-bottom: 5px;
                }

                .product-grid table tbody tr td .product-info-overlay p {
                    font-size: 18px;
                    margin-bottom: 15px;
                }

                .product-grid table tbody tr td .product-info-overlay i {
                    width: 30px;
                    height: 30px;
                    display: inline-block;
                    margin: 0 8px;
                    background-size: cover;
                    cursor: pointer;
                    transition: transform 0.2s ease-in-out;
                }

                    .product-grid table tbody tr td .product-info-overlay i:hover {
                        transform: scale(1.1);
                    }

                    .product-grid table tbody tr td .product-info-overlay i.add-to-cart-btn {
                        background-image: url('../Images/Icon/Icon2.png'); /* Giỏ hàng */
                    }

                    .product-grid table tbody tr td .product-info-overlay i.view-details-btn {
                        background-image: url('../Images/Icon/Icon1.png'); /* Thông tin */
                    }


.pagination {
    position: fixed;
    left: 0;
    bottom: 0;
    width: calc(100% - 50px); /* Kích thước trừ menu phải */
    text-align: center;
    padding: 15px;
    box-sizing: border-box;
    box-shadow: 0px -1px 15px 0px rgba(0, 0, 0,.1);
    background: #fff;
    z-index: 5;
}

    .pagination:after {
        content: '';
        position: absolute;
        left: 0;
        top: 0;
        background: #67b968;
        width: 100%;
        height: 3px;
    }

    .pagination button {
        background: #fff;
        border: 1px solid rgba(0, 0, 0,.2);
        height: 35px;
        padding: 0px 15px;
        border-radius: 5px;
        margin: 0 5px;
        cursor: pointer;
        transition: background-color 0.2s, color 0.2s;
    }

        .pagination button:hover:not(.active) {
            background: #eee;
        }

    .pagination button.active {
        background: #67b968 !important;
        color: #fff;
        border-color: #67b968;
    }

    .pagination button, .pagination .page-numbers {
        display: inline-block;
    }

/* Menu bên phải */
.side-menu {
    position: fixed;
    top: 70px; /* Dưới header */
    right: 0px;
    background: #fff;
    width: 50px;
    height: calc(100% - 70px); /* Từ dưới header đến hết trang */
    z-index: 10;
    box-shadow: -2px 0 5px rgba(0,0,0,0.1);
}

    .side-menu::after {
        content: '';
        left: 0px;
        top: 0px;
        height: 100%;
        width: 3px;
        background: #67b968;
        position: absolute;
    }

    .side-menu .menu-list {
        list-style: none;
        padding: 0;
        margin: 0;
    }

    .side-menu .menu-list .menu-item {
        position: relative;
        padding: 10px 0;
        text-align: center;
        cursor: pointer;
    }

        .side-menu .menu-list .menu-item:hover {
            background: rgba(0,0,0,0.1);
        }

        .side-menu .menu-list .menu-item .icon-info,
        .side-menu .menu-list .menu-item .icon-cart {
            display: block;
            width: 32px;
            height: 32px;
            background-repeat: no-repeat;
            background-position: center;
            background-size: 80%;
            margin: 0 auto;
        }

        .side-menu .menu-list .menu-item .icon-info {
            background-image: url('../Images/Icon/Icon1.png');
        }
        .side-menu .menu-list .menu-item .icon-cart {
            background-image: url('../Images/Icon/Icon2.png');
        }

        .side-menu .menu-list .menu-item .cart-dropdown {
            position: absolute;
            right: 50px;
            top: 0px;
            width: 300px;
            max-height: 400px;
            background: #fff;
            border: 3px solid #67b968;
            border-right: none;
            box-sizing: border-box;
            list-style: none;
            padding: 0;
            margin: 0;
            box-shadow: -5px 0 10px rgba(0,0,0,0.1);
        }

            .side-menu .menu-list .menu-item .cart-dropdown .cart-items-container {
                max-height: 350px;
                overflow-y: auto;
                padding: 10px;
            }

                .side-menu .menu-list .menu-item .cart-dropdown .cart-items {
                    list-style: none;
                    padding: 0;
                    margin: 0;
                }

                    .side-menu .menu-list .menu-item .cart-dropdown .cart-items .cart-item-entry {
                        position: relative;
                        padding: 8px 0;
                        display: flex;
                        align-items: center;
                        border-bottom: 1px solid rgba(0,0,0,0.1);
                    }

                        .side-menu .menu-list .menu-item .cart-dropdown .cart-items .cart-item-entry:last-child {
                            border-bottom: none;
                        }

                        .side-menu .menu-list .menu-item .cart-dropdown .cart-items .cart-item-entry img {
                            width: 60px;
                            height: 60px;
                            object-fit: cover;
                            border-radius: 4px;
                            margin-right: 10px;
                        }

                        .side-menu .menu-list .menu-item .cart-dropdown .cart-items .cart-item-entry p {
                            flex-grow: 1;
                            margin: 0;
                            line-height: 1.4;
                            font-size: 14px;
                        }

                            .side-menu .menu-list .menu-item .cart-dropdown .cart-items .cart-item-entry p label {
                                font-weight: bold;
                                display: block;
                            }
                            .side-menu .menu-list .menu-item .cart-dropdown .cart-items .cart-item-entry p .item-price {
                                color: #67b968;
                            }


.remove-from-cart-btn {
    position: absolute;
    right: 5px;
    top: 5px;
    font-size: 12px;
    color: #f44336;
    cursor: pointer;
    background: none;
    border: none;
    padding: 0 5px;
}
    .remove-from-cart-btn:hover {
        color: #d32f2f;
    }


.checkout-area {
    width: 100%;
    padding: 0;
    margin-top: 5px;
}

    .checkout-area button {
        display: block;
        width: 100%;
        height: 45px;
        color: #fff;
        background: #67b968;
        border: none;
        font-size: 16px;
        cursor: pointer;
        transition: background-color 0.2s;
    }

        .checkout-area button:hover {
            background: #559856;
        }

/* Điều khiển số lượng */
.quantity-control {
    display: flex;
    align-items: center;
    margin-left: 10px;
    border: 1px solid #67b968;
    border-radius: 4px;
    overflow: hidden;
}

    .quantity-control button {
        background: none;
        border: none;
        width: 25px;
        height: 25px;
        font-size: 16px;
        cursor: pointer;
        color: #67b968;
        transition: background-color 0.2s, color 0.2s;
    }

        .quantity-control button:hover {
            background: #67b968;
            color: #fff;
        }

    .quantity-control input[type="number"] {
        width: 40px;
        height: 25px;
        text-align: center;
        border: none;
        border-left: 1px solid #67b968;
        border-right: 1px solid #67b968;
        -moz-appearance: textfield; /* Firefox */
        font-size: 14px;
    }

        .quantity-control input[type="number"]::-webkit-outer-spin-button,
        .quantity-control input[type="number"]::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
    

Logic Backend (ASP.NET MVC Controller)

Ở phía server, một Controller (ví dụ: ShopController) sẽ xử lý các yêu cầu AJAX từ phía client để lấy dữ liệu sản phẩm và quản lý giỏ hàng. Dưới đây là các ví dụ về các action method:


using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace YourApplication.Controllers
{
    public class ShopController : Controller
    {
        // Mô hình dữ liệu giả định
        public class ProductViewModel
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public decimal Price { get; set; }
            public string ImageUrl { get; set; }
        }

        public class CartItemViewModel
        {
            public int CartID { get; set; }
            public int UserID { get; set; }
            public ProductViewModel Product { get; set; }
            public int Quantity { get; set; }
        }

        // Dữ liệu sản phẩm giả định
        private static List<ProductViewModel> _mockProducts = new List<ProductViewModel>
        {
            new ProductViewModel { ID = 1, Name = "Bò né đặc biệt", Price = 55.00M, ImageUrl = "/Content/Images/Greens/A_1.png" },
            new ProductViewModel { ID = 2, Name = "Mì Ý Carbonara", Price = 60.00M, ImageUrl = "/Content/Images/Greens/A_2.png" },
            new ProductViewModel { ID = 3, Name = "Gà rán giòn", Price = 45.00M, ImageUrl = "/Content/Images/Greens/A_3.png" },
            new ProductViewModel { ID = 4, Name = "Bánh mì kẹp", Price = 30.00M, ImageUrl = "/Content/Images/Greens/A_4.png" },
            new ProductViewModel { ID = 5, Name = "Salad rau củ", Price = 35.00M, ImageUrl = "/Content/Images/Greens/A_5.png" },
            new ProductViewModel { ID = 6, Name = "Phở cuốn", Price = 40.00M, ImageUrl = "/Content/Images/Greens/A_6.png" },
            new ProductViewModel { ID = 7, Name = "Nước cam tươi", Price = 25.00M, ImageUrl = "/Content/Images/Greens/A_7.png" },
            new ProductViewModel { ID = 8, Name = "Bánh tiramisu", Price = 70.00M, ImageUrl = "/Content/Images/Greens/A_8.png" },
            new ProductViewModel { ID = 9, Name = "Sushi tổng hợp", Price = 120.00M, ImageUrl = "/Content/Images/Greens/A_9.png" },
            new ProductViewModel { ID = 10, Name = "Canh chua cá", Price = 65.00M, ImageUrl = "/Content/Images/Greens/A_10.png" },
            new ProductViewModel { ID = 11, Name = "Cơm chiên hải sản", Price = 80.00M, ImageUrl = "/Content/Images/Greens/A_11.png" },
            new ProductViewModel { ID = 12, Name = "Chè khoai môn", Price = 20.00M, ImageUrl = "/Content/Images/Greens/A_12.png" }
        };

        // Dữ liệu giỏ hàng giả định (trong thực tế sẽ lưu trong database)
        private static List<CartItemViewModel> _mockCartItems = new List<CartItemViewModel>();
        private static int _nextCartId = 1;

        // GET: Shop/GetProducts
        public ActionResult GetProducts()
        {
            // Trả về tất cả sản phẩm
            return Json(_mockProducts, JsonRequestBehavior.AllowGet);
        }

        // GET: Shop/GetCartItems
        public ActionResult GetCartItems(int userId)
        {
            var userCart = _mockCartItems
                            .Where(item => item.UserID == userId)
                            .ToList();
            return Json(userCart, JsonRequestBehavior.AllowGet);
        }

        // POST: Shop/AddProductToCart
        [HttpPost]
        public ActionResult AddProductToCart(int userId, int productId, int quantity = 1)
        {
            var existingItem = _mockCartItems.FirstOrDefault(item => item.UserID == userId && item.Product.ID == productId);
            if (existingItem != null)
            {
                existingItem.Quantity += quantity;
                return Json(new { Success = true, Message = "Đã cập nhật số lượng sản phẩm trong giỏ hàng." });
            }
            else
            {
                var product = _mockProducts.FirstOrDefault(p => p.ID == productId);
                if (product == null)
                {
                    return Json(new { Success = false, Message = "Sản phẩm không tồn tại." });
                }

                _mockCartItems.Add(new CartItemViewModel
                {
                    CartID = _nextCartId++,
                    UserID = userId,
                    Product = product,
                    Quantity = quantity
                });
                return Json(new { Success = true, Message = "Đã thêm sản phẩm vào giỏ hàng." });
            }
        }

        // POST: Shop/UpdateCartItemQuantity
        [HttpPost]
        public ActionResult UpdateCartItemQuantity(int cartItemId, int newQuantity)
        {
            var itemToUpdate = _mockCartItems.FirstOrDefault(item => item.CartID == cartItemId);
            if (itemToUpdate == null)
            {
                return Json(new { Success = false, Message = "Mục giỏ hàng không tồn tại." });
            }
            if (newQuantity <= 0)
            {
                 _mockCartItems.Remove(itemToUpdate); // Xóa nếu số lượng là 0 hoặc âm
                 return Json(new { Success = true, Message = "Đã xóa sản phẩm khỏi giỏ." });
            }

            itemToUpdate.Quantity = newQuantity;
            return Json(new { Success = true, Message = "Đã cập nhật số lượng sản phẩm." });
        }

        // POST: Shop/RemoveCartItem
        [HttpPost]
        public ActionResult RemoveCartItem(int cartItemId)
        {
            var itemToRemove = _mockCartItems.FirstOrDefault(item => item.CartID == cartItemId);
            if (itemToRemove == null)
            {
                return Json(new { Success = false, Message = "Mục giỏ hàng không tồn tại." });
            }

            _mockCartItems.Remove(itemToRemove);
            return Json(new { Success = true, Message = "Đã xóa sản phẩm khỏi giỏ hàng." });
        }
    }
}
    

Thẻ: ASP.NET MVC jQuery ajax Shopping Cart Product Listing

Đăng vào ngày 25 tháng 7 lúc 12:07