-
글쓴이글
-
2023년 8월 9일 16:51 #94089
동둥당참가자안녕하세요, 저는 자바스크립트로 진행하고 있는데 도저히 모르겠어서 질문드립니다. 검색기능과 진열기능은 일단 작동이 됩니다. 이제 담기버튼과 드래그&드롭을 하는데 Uncaught TypeError: Cannot read properties of null (reading 'addEventListener') 이런말이 계속 나오고 드래그&드롭에서는 dataset.id를 들어가면 id가 나오질 않네요. 선생님 답에는 dataset.id이 들어가있는걸 확인했습니다. 검색을 해보니
에러 원인이 HTML이 모두 로드 되기 전에 자바스크립트 영역에서 HTML을 참조하기 때문이라 하더라구요. 그래서 의심이 가는 부분이 js파트에서 백틱으로 친 부분들에게 있다고 생각을 했습니다. 그래서 답을 보니 제이쿼리는 가능한거 같더라구요. 자바스크립트 답안지가 있다면 좋겠지만 없는거 같아서 질문 남깁니다 ㅠㅠ 제가 어디서부터 잘못된건지 짚어주시면 다시 도전해보겠습니다. 많은 가르침 부탁드려요ㅜ
________________________________________________________________ HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous" /> <link rel="stylesheet" href="./index.css" /> <title>Document</title> </head> <body> <!-- nav --> <nav class="navbar navbar-expand-md navbar-dark bg-dark"> <div class="container-fluid"> 집꾸미기 <div class="collapse navbar-collapse" id="navbarCollapse"> <ul class="navbar-nav me-auto mb-2 mb-md-0"> <li class="nav-item"> Home
<li class="nav-item"> 스토어
<li class="nav-item"> 시공견적
</div> </div> </nav> <!-- 검색어 창 --> <div class="container"> <div class="row"> <form class="d-flex mt-3 col-2" role="search"> <input class="form-control me-2" type="search" placeholder="검색어 입력" aria-label="Search" /> </form> </div> </div> <!-- 카드들 모음 --> <div class="container"> <div class="row cards drag-img"></div> </div>
<!-- 장바구니 -->
<div class="container basket-wrap" style="background: #e2e2e2"> <h4>장바구니 (드래그 가능)</h4> <div class="row basket"></div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous" ></script> <script src="./index.js"></script> </body> </html>
________________________________________________________________
CSS
* { margin: 0; box-sizing: border-box; }
.basket { min-height: 300px; width: 100%; background: black; padding: 0px; }
.basket-wrap { padding: 30px; margin-top: 30px; }
________________________________________________________________
JS
const input = document.querySelector(".form-control"); const cards = document.querySelector(".cards");
// 상품 보여주기 let products = [];
fetch("./store.json") .then((res) => res.json()) .then((data) => { // 원본데이터 다른데서 많이 쓰니까 변수에 보관 products = data.products;
// 페이지로드시 json 데이터 가져와서 메인페이지 내용 만들기 data.products.forEach((a, i) => { let 템플릿 = ` <div class="col-sm-3 mt-3 " data-id=${a.id}> <div class="item" draggable="true" > < img src="${a.photo}" class="w-100"> <h5>${a.title}</h5> <h6>${a.brand}</h6> <p>가격 : ${products[i].price}</p> <button class="add" data-id="${a.id}">담기</button> </div> </div>`; console.log(`${a.id}`); cards.insertAdjacentHTML("beforeend", 템플릿); }); });
input.addEventListener("change", (e) => { let 검색어 = e.target.value;
// 지금 입력한 글자가 제목에 있으면 let products에서 검색어 있는것만 남기기
let newProducts = products.filter((a) => { return a.title.includes(검색어) || a.brand.includes(검색어); });
// 카드 초기화 시키기 cards.innerHTML = ""; // 검색한 결과로 카드 나타내주기 newProducts.forEach((a, i) => { let 템플릿 = ` <div class="col-sm-3 mt-3 "> <div class="" draggable="true"> < img src="${a.photo}" class="w-100"> <h5>${a.title}</h5> <h6>${a.brand}</h6> <p>가격 : ${products[i].price}</p> <button class="add" data-id="${a.id}">담기</button> </div> </div>`; cards.insertAdjacentHTML("beforeend", 템플릿); }); });
// 담기버튼 누르기 let add = document.querySelector(".add"); add.addEventListener("click", () => { console.log("담기"); });
// 드래그 이벤트
let item = document.querySelector(".item"); const basket = document.querySelector(".basket");
let cardNumber = 0;
// 드래그 이벤트 발생요소 item.addEventListener("dragstart", function (e) { console.log(e); });
basket.addEventListener("dragover", (e) => { e.preventDefault(); }); basket.addEventListener("drop", (e) => { let productId = e.dataTransfer.getData("id"); console.log(productId); });
2023년 8월 14일 14:36 #94621
동둥당참가자선생님 우선 담아지기 한개 가능, 총 가격은 나옵니다. 1. 첫번째 상품인 식기세척기를 드래그 했을때 e.target.dataset.id가 undefined으로 나옵니다. 이벤트리스너들을 data.products.forEach() 바로 다음줄에 옮기라고 하셨는데
순서대로 나열한거 같은데 나오질 않아서 모르겠습니다..고민을 많이했는데도 이 부분은 모르겠습니다.
2. 담기버튼과 드래그를 할때 한개만 작동이 됩니다.
담기버튼을 누를때 첫번째꺼만 누르면 잘 담기고 가격도 잘 나옵니다. 그러나 여러개 상품이 있으니 let add = document.querySelectorAll(".add"); 이렇게 해준뒤 누르려고 하면
index.js:36 Uncaught (in promise) TypeError: add.addEventListener is not a function at index.js:36:9 라고 뜨네요. add[1].addeventlistener라고 하면 다른 것들도 담아집니다. 제이쿼리랑 자바스크립트의 차이로 제가 잘 모르는것인지 궁굼합니다. 혹은 모든 버튼이 동작하려면
forEach함수를 사용해야 하는 것일까요? _______________________________________________________________________ HTML
<!-- nav --> <nav class="navbar navbar-expand-md navbar-dark bg-dark"> <div class="container-fluid"> 집꾸미기 <div class="collapse navbar-collapse" id="navbarCollapse"> <ul class="navbar-nav me-auto mb-2 mb-md-0"> <li class="nav-item"> Home
<li class="nav-item"> 스토어
<li class="nav-item"> 시공견적
</div> </div> </nav> <!-- 검색어 창 --> <div class="container"> <div class="row"> <form class="d-flex mt-3 col-2" role="search"> <input class="form-control me-2" type="search" placeholder="검색어 입력" aria-label="Search" /> </form> </div> </div> <!-- 카드들 모음 --> <div class="container"> <div class="row cards drag-img"></div> </div>
<!-- 장바구니 -->
<div class="container basket-wrap" style="background: #e2e2e2"> <h4>장바구니 (드래그 가능)</h4> <div class="row basket"></div> </div>
<!-- 가격 --> <div class="container my-3"> <h4>최종가격</h4> <p class="final-price"></p> <button class="buy">구매하기</button> </div>
<!-- 모달 --> <div class="modal1" style="display: none"> <div class="white-bg"> <h4>성함</h4> <input type="text" id="name" /> <h4>연락처</h4> <input type="text" id="phone" /> <button class="show-receipt">입력완료</button> <div> <button class="close">닫기</button> </div> </div> </div>
<!-- 영수증 모달 --> <div class="modal2" style="display: none"> <div class="white-bg"> <h4>영수증</h4> <canvas id="canvas" width="350" height="350"></canvas> <div> <button class="close">닫기</button> </div> </div> </div> _______________________________________________________________________ CSS
* { margin: 0; box-sizing: border-box; }
.basket { min-height: 300px; width: 100%; background: black; padding: 0px; }
.basket-wrap { padding: 30px; margin-top: 30px; } .basket div { padding: 15px; border-radius: 5px; }
.item { background: white; padding: 20px; margin-top: 20px; }
_______________________________________________________________________ JS
const input = document.querySelector(".form-control"); const cards = document.querySelector(".cards"); const final = document.querySelector(".final-price"); let add = document.querySelector(".add");
// 상품 보여주기 let products = []; let cart = [];
fetch("./store.json") .then((res) => res.json()) .then((data) => { // 원본데이터 다른데서 많이 쓰니까 변수에 보관 products = data.products;
// 페이지로드시 json 데이터 가져와서 메인페이지 내용 만들기 data.products.forEach((a, i) => { let 템플릿 = ` <div class="col-sm-3 mt-3 " data-id=${a.id}> <div class="item" draggable="true" > < img src="${a.photo}" class="w-100"> <h5>${a.title}</h5> <h6>${a.brand}</h6> <p>가격 : ${products[i].price}</p> <button class="add" data-id="${a.id}">담기</button> </div> </div>`;
cards.insertAdjacentHTML("beforeend", 템플릿); });
// 담기버튼 누르기
let add = document.querySelector(".add"); add.addEventListener("click", (e) => { //지금 누른 상품번호 let productId = e.target.dataset.id; console.log(productId); //담기버튼 누를때 let cart = []에 상품을 {} 형태로 보관부터 하고
//let cart에 상품이 이미있는지 찾고,없으면 let cart에 {}추가, 있으면 수량만 ++;
let 몇번째 = cart.findIndex((a) => { return a.id == productId; });
if (몇번째 == -1) { let 현재상품 = products.find((a) => { return a.id == productId; }); 현재상품.count = 1; cart.push(현재상품); } else { cart[몇번째].count++; }
// 담기버튼 누를 때 마다 장바구니 박스에 let cart 안에 있던{} 갯수만큼 html 생성 basket.innerHTML = ""; cart.forEach((a, i) => { let 템플릿 = ` <div class="col-sm-3 mt-3"> <div class="item"> < img src="${a.photo}" class="w-100"> <h5>${a.title}</h5> <h6>${a.brand}</h6> <p class='item-price'> ${products[i].price}</p> <input type='number' value='${a.count}' class='item-count w-100' /> </div> </div>`;
basket.insertAdjacentHTML("beforeend", 템플릿); console.log(a.count); });
// 총가격 계산해서 표기해주는 기능 가격계산();
//input값 조절해도 총가격 계산해서 표기해줘야될듯 const itemCount = document.querySelector(".item-count");
itemCount.addEventListener("input", () => { 가격계산(); }); }); // add버튼 끝
// 드래그 이벤트 let item = document.querySelector(".item"); let basket = document.querySelector(".basket");
// 드래그 이벤트 발생요소 item.addEventListener("dragstart", function (e) { console.log(e); }); basket.addEventListener("dragover", (e) => { e.preventDefault(); }); basket.addEventListener("drop", (e) => { let productId = e.dataTransfer.getData("id"); }); });
// 총 가격 계산해서 표기해주는 기능 function 가격계산() { let finalPrice = 0; const itemCount = document.querySelectorAll(".item-count"); const itemPrice = document.querySelectorAll(".item-price");
for (let i = 0; i < itemCount.length; i++) { let price = itemPrice[i].innerText; let count = itemCount[i].value; finalPrice += parseFloat(price * count); } console.log(finalPrice); final.innerHTML = finalPrice; }
input.addEventListener("change", (e) => { let 검색어 = e.target.value;
// 지금 입력한 글자가 제목에 있으면 let products에서 검색어 있는것만 남기기
let newProducts = products.filter((a) => { return a.title.includes(검색어) || a.brand.includes(검색어); });
// 카드 초기화 시키기 cards.innerHTML = ""; // 검색한 결과로 카드 나타내주기 newProducts.forEach((a, i) => { let 템플릿 = ` <div class="col-sm-3 mt-3 "> <div class="" draggable="true"> < img src="${a.photo}" class="w-100"> <h5>${a.title}</h5> <h6>${a.brand}</h6> <p>가격 : ${products[i].price}</p> <button class="add" data-id="${a.id}">담기</button> </div> </div>`; cards.insertAdjacentHTML("beforeend", 템플릿); }); });
2023년 8월 14일 19:02 #94650
codingapple키 마스터.add 달린 버튼은 여러개인데 지금은 첫째 .add 버튼에만 이벤트리스너 붙인듯요 querySelectorAll로 찾은건 뒤에 [] 붙여서 씁시다
-
글쓴이글
- 답변은 로그인 후 가능합니다.