未捕获的类型错误:无法读取 null Javascipt

时间:2021-07-09 16:53:56

标签: javascript html css

我有一个对象列表或数组,我通过模板将这些对象传递给 HTML 元素。我有一个 removeItem 函数。它正在删除项目。但是在最后一项上,它并没有隐藏它。当菜单中没有项目时,我试图隐藏菜单。但是在最后一个项目上,它被卡住了,不再做任何事情。模板导致了所有问题。除了该模板隐藏之外,所有其他项目都是如此。但事实并非如此。我的shoppingCart.js 将cartRemove.classList.add("hide") 设为null。 .hide 具有 display:none 属性。 错误:

Uncaught TypeError: Cannot read property 'classList' of null
    at hideCart (shoppingCart.js:74)
    at renderCart (shoppingCart.js:54)
    at removeFromCart (shoppingCart.js:68)
    at HTMLDocument.<anonymous> (shoppingCart.js:29)

Gif of my Problem

shoppingCart.js

import items from "./items.json";
import { formatCurrency } from "./utils/formatCurrency.js";

const menu = document.querySelector(".menu");
const cart = document.querySelector("#cart");
const cartRemove = document.querySelector("[data-cart-item]");

const storeCartContainer = document.querySelector("[data-cart-container]");
const cartItemTemplate = document.querySelector("#cart-item-template");
const cartQuantity = document.querySelector("[data-cart-quantity]");
const cartTotal = document.querySelector("[data-cart-total]");
const cartHide = document.querySelector(".ahmad");
// total.innerHTML = cartTotal.innerText
   

let shoppingCart = [];
const IMAGE_URL = "https://dummyimage.com/420x220";

export const toggleCard = cart.addEventListener("click", () => {
  menu.classList.toggle("show");
});

export function setupShoppingCart() {
    document.addEventListener("click", (e) => {
      e.preventDefault()
    if (e.target.matches("[data-remove-to-cart-button]")) {
      const id = parseInt(e.target.closest("[data-cart-item]").dataset.itemId);
        removeFromCart(id);
        if (id === null) {
            renderCart()
        }
    }
  });
    renderCart();
}

export function addToCart(id) {

    const existingItem = shoppingCart.find(entry => entry.id === id)
    if (existingItem) {
        existingItem.quantity++
    }
    else {
     shoppingCart.push({ id: id, quantity: 1 });
    }


  renderCart();
}

function renderCart() {
    if (shoppingCart.length === 0) {
        hideCart()
        // hideData()

    }
    else {
        showCart()
        renderCartItems();
    }
}

function removeFromCart(id) {
  const existingItem = shoppingCart.find((entry) => entry.id === id);
  if (existingItem == null) return;
  shoppingCart = shoppingCart.filter((entry) => entry.id !== id);
  renderCart();

    }
    
    function hideCart() {
      cartHide.classList.add("hide");
    
  cartRemove.classList.add("hide"); // This is getting Null
    }
function showCart() {
    cart.classList.remove("hide")

}

function renderCartItems() {
    cartQuantity.innerText = shoppingCart.length;

    const totalCents = shoppingCart.reduce((sum, entry) => {
        const item = items.find((i) => entry.id === i.id);
        return sum + item.priceCents * entry.quantity

    },0)

    cartTotal.innerText = formatCurrency(totalCents / 100)
    storeCartContainer.innerHTML = "";

    shoppingCart.forEach((entry) => {
        console.log(items, entry);

        const item = items.find((i) => entry.id === i.id);
        const cartItem = cartItemTemplate.content.cloneNode(true);

        const container = cartItem.querySelector("[data-cart-item]");
        container.dataset.itemId = item.id;

        const name = cartItem.querySelector("[data-cart-name]");
        name.innerText = item.name;
        if (entry.quantity > 1) {
            const quantity = cartItem.querySelector("[data-cart-quantity]");
            quantity.innerText = `x${entry.quantity}`;
        }

        const image = cartItem.querySelector("[data-cart-img]");
        image.src = `${IMAGE_URL}/${item.imageColor}/${item.imageColor}`;

    const price = cartItem.querySelector("[data-cart-price]");

    price.innerText = formatCurrency((item.priceCents * entry.quantity) / 100);

    storeCartContainer.appendChild(cartItem);
  });
};

store.index

  </head>
  <body>
    <div class="container">
      <div class="front-page">
        <!-- Section 1 -->
        <section class="section-1">
          <a href="#" id="cart" class="ahmad">
            <i class="fas fa-shopping-cart"></i>
            <span data-cart-quantity></span>
          </a>
          <div>
              <div class="menu">
              <div data-cart-container> //Template is under this div
                  <div>
                  </div>
                   </div>
                    <div class="details">
                        <h5>Total</h5>
                         <div data-cart-total>
                         </div> </div>
                </div>
        </section>
</body>
</head>
     <template id="cart-item-template">
             <div data-cart-item class="palette">
            <button data-remove-to-cart-button>Close</button>
                <img data-cart-img class="bgc-menu"></img>
                <div class="palette-detail">
                <div data-cart-name class="palette-color"></div>
                <div data-cart-quantity></div>
                <div data-cart-price class="palette-price"></div>
                </div>
                <!-- <span data-cart-amount class="plz">$0.00</span> -->        
        </template>

2 个答案:

答案 0 :(得分:0)

根据this answer,要在模板中定位元素,您需要querySelector使用模板的content关键字,如下所示:

const template = document.querySelector("#cart-item-template");
const cartRemove = template.content.querySelector("[data-cart-item]");
cartRemove.classList.add("hide"); // Now it works fine

答案 1 :(得分:0)

您试图在脚本开头引用模板中的元素:

const cartRemove = document.querySelector("[data-cart-item]");

这发生在您的模板被克隆并放入 DOM 之前,因此此时未找到具有 data-cart-item 属性的元素 - 您在 null 变量中获得 cartRemove

renderCartItems 函数中实例化模板并通过特定实例(如您在这两行中所做的那样)之后,尝试选择此元素:

const cartItem = cartItemTemplate.content.cloneNode(true);
const container = cartItem.querySelector("[data-cart-item]");