localStorage를 이용한 장바구니 개발 마무리해야한다!
로컬스토리지에 저장한 key값이 순서가 뒤죽박죽 되어버리는 문제를 어떻게 해결할 것인가? 찾아보니 비슷한 질문을 하신 분이 있었다!
https://www.inflearn.com/questions/38188
아무래도 우선 로컬스토리지의 데이터를 전부 다 불러와서 어딘가 저장한 뒤에, 그걸 다시 sort로 정렬을 하고 그 정렬된 데이터를 가지고 처리하는 방식을 시도해봐야겠다.
localStorage.getItem(key)로 값 가져오고 나서,
["id"]를 해도 id값이 안 나와서 뭐지, 했는데
JSON형태라서 console.log로 찍어봤을 때는 모양이 꼭 객체처럼 생겨서 객체를 가져온 것 같지만 사실 그냥 string type이었기 때문...
JSON.parse(localStorage.getItem(key))로 객체로 만들어서 저장해준 다음 ["id"]하니까 잘만 나온다. 헤헤.
if (localStorage.length > 0) {
for (let i = 0; i < localStorage.length; i++) {
if (Number(index) < Number(localStorage.key(i))) { //maxIndex 구하기
index = localStorage.key(i);
var cartItem = JSON.parse(localStorage.getItem(localStorage.key(i)));
if ( //menu와 option이 같으면 같은 메뉴이므로 price와 count만 바꿔준다
JSON.stringify(cartItem.menu) == JSON.stringify(menu) &&
JSON.stringify(cartItem.option) == JSON.stringify(option)
) {
isSame = true;
price = cartItem.price;
count = cartItem.count;
break;
}
}
}
}
구글에서 찾은 선배님의 소스코드 중 일부를 아래와 같이 수정했다.(key값이 순서대로 나오지 않는 문제를 해결하기 위해) -> localStorage.key() 를 쓰지 않고 .getItem()으로 변경
for (let i = 0; i < localStorage.length; i++) {
if (Number(index) < Number(localStorage.key(i))) { //maxIndex 구하기
index = localStorage.key(i);
for (let i = 1; i < localStorage.length+1; i++) {
if (Number(index) < i) { //maxIndex 구하기
let cartItem = JSON.parse(localStorage.getItem(i))
index = cartItem.id;
(for문을 통해 localStorage.key(0)을 넣으면 맨 처음 넣은 녀석이 나와야하는데 두번째로 넣은 녀석이 나와서 문제가 생겼었다)
if (localStorage.length > 0) {
for (let i = 1; i < localStorage.length+1; i++) {
if (Number(index) < i) { //maxIndex 구하기
let cartItem = JSON.parse(localStorage.getItem(i))
index = cartItem.id;
//menu 이름이 같으면 같은 메뉴
if(JSON.stringify(cartItem.menu) === JSON.stringify(menu)){
isSame = true;
price = cartItem.price;
count = cartItem.count;
break;
}
}
}
}
HTML
<div class="card-body">
<a target="_blank" href="#" class="card-title">어묵볶음</a>
<p class="card-text">가격 : <span class="price">4000</span></p>
<p class="card-text comment">수량 : <span class="count">1</span></p>
<button onclick="addToCart(this)">장바구니 넣기</button>
</div>
javascript
function addToCart(e){
const menu = $(e).closest('div').find('a').text();
let price_new = $(e).closest('div').find('.price').text();
let count_new = $(e).closest('div').find('.count').text();
let img_url = $(e).closest('div').siblings('img').attr('src');
let price = 0;
let count = 0;
let index = 0; //새로운 메뉴가 들어갈 index (maxIndex + 1)
let isSame = false; //중복되는 메뉴가 있는지
let value = [];
if (localStorage.length > 0) {
for (let i = 1; i < localStorage.length+1; i++) {
if (Number(index) < i) { //maxIndex 구하기
let cartItem = JSON.parse(localStorage.getItem(i))
index = cartItem.id;
//menu 이름이 같으면 같은 메뉴
if(JSON.stringify(cartItem.menu) === JSON.stringify(menu)){
isSame = true;
price = cartItem.price;
count = cartItem.count;
break;
}
}
}
}
if (isSame === true) { //중복되는 물건이 장바구니에 있는 경우 price와 count만 바꿔준다
value = {
id: Number(index),
menu: menu,
price: Number(price) + Number(price_new),
count: Number(count) + Number(count_new),
img_url: img_url
};
} else { //새로운 메뉴인 경우 maxIndex + 1을 key로 하여 저장한다
index = Number(index) + 1;
value = {
id: Number(index),
menu: menu,
price: Number(price_new),
count: Number(count_new),
img_url: img_url
};
}
localStorage.setItem(index, JSON.stringify(value)); //localStorage에 저장
}
<script>
$(document).ready(function () {
showOrders();
});
function showOrders(){
let temp_html = ``;
let menu = '';
let price = 0;
let count = 0;
let index = 0;
let img_url = '';
let price_all = 0;
if (localStorage.length > 0) {
for (let i = 1; i < localStorage.length+1; i++) {
let cartItem = JSON.parse(localStorage.getItem(i))
index = cartItem.id;
menu = cartItem.menu;
price = cartItem.price;
count = cartItem.count;
img_url = cartItem.img_url;
price_all += Number(price)
temp_html += `
<tr>
<td>${index}</td>
<td><img class="thumbnail" src="${img_url}" /></td>
<td>${menu}</td>
<td>${count}<button class="plus">+</buttn><button class="minus">-</button></td>
<td>${price}원</td>
<td>${price_all}원</td>
</tr>
`;
}
}
$("#orderTable").append(temp_html)
}
</script>
개선할 사항:
1. 금액합계인 price_all은 마지막에만 따로 보여줄 것
2. 장바구니에서 + - 버튼으로 각 상품별 수량조절하거나 특정 메뉴 삭제하는 기능 추가 구현 필요
삭제버튼을 만들어 위쪽의 key값이 1인 메뉴를 장바구니에서 삭제하였더니 for문에서 에러가 발생.
i = 1부터 순서대로 도는데,
key값이 1인 메뉴가 사라지니 let cartItem = JSON.parse(localStorage.getItem(i))
에 값이 없고, 그에 따라 뒤에 코드들에 에러 발생하는 것으로 보임.
장바구니에 데이터 넣는 코드에는 if문에 localStorage.getItem(i) !== null 라는 조건을 추가하고,
localStorage의 데이터를 가져와 장바구니에 담긴 메뉴들을 보여주는 코드에는 if문을 새로 하나 만들어 localStorage.getItem(i) !== null라는 조건을 추가했다.
그랬더니 또 다른 에러가 발생했는데, localStorage.length를 이용해 for문의 반복횟수를 결정하다보니 삭제에 따라 length값은 줄었는데 남아있는 key값은 2. length는 1이라 for문은 한번밖에 안 돌아서 key값이 2인 주문을 불러오지를 못했다.
대략 아래 네 가지 정도의 해결방법을 생각해봤다.
1. 반복문의 반복횟수를 localStorage.length가 아닌 다른 방식으로 구현해서 실제 값이 있는 데이터들만 불러오기
2. 삭제할 때 key값까지 다 삭제하지말고 value쪽만 삭제하는 방식 -> 목록에서 보이는 숫자도 따로 신경써주어야함
3. 아예 메뉴 하나당 key하나를 할당하지말고 장바구니라는 하나의 key에 value로 객체 안의 객체로 다 넣고, 생성이나 삭제 시 전체 객체를 불러와서 재정렬 후 다시 전부를 갱신시키는 방법
4. 삭제할 때 삭제 한 뒤 남은 데이터들을 불러와서 key값을 앞에서부터 채우도록 재정렬해서 넣는 코드를 짜서 같이 돌리기
4번째 방법을 우선 채택했다. key값을 낮은 숫자부터 순서대로 돌리는 for문이 양쪽(장바구니 담기와 삭제)에서 다 쓰이고 있어서, key값이 중간이 빈 채로 있으면 곤란하다.
function deleteMenu(e){
//현재 버튼 누른 메뉴의 index값 불러와서 localStorage에서 삭제
let del_index = $(e).closest('tr').find('.index').text();
localStorage.removeItem(del_index);
//localStorage의 남은 값들을 모두 불러와서 index를 앞쪽숫자부터 다시 부여해서 순서대로 재등록(index와 cart페이지의 for문이 정상적으로 돌도록)
if (localStorage.length > 0) {
//새로운 index를 앞에서부터 차례로 부여해주기 위한 j 변수 선언
let j = 0;
//+2인 이유: 0부터가 아닌 1부터 시작하므로 +1, 이미 지워진 하나때문에 값이 하나씩 밀려있으므로 getItem(i)가 끝까지 다 가려면 +1
for (let i = 1; i < localStorage.length+2; i++) {
if (localStorage.getItem(i) !== null) {
j++;
//전부 가져와서 그대로 재등록하기.(key, id값만 변경됨)
let cartItem = JSON.parse(localStorage.getItem(i))
//console.log(cartItem)
let index = j;
let id = Number(index);
let menu = cartItem.menu;
let price = cartItem.price;
let count = cartItem.count;
let img_url = cartItem.img_url;
let value = {
id: id,
menu: menu,
price: price,
count: count,
img_url: img_url
};
//지금 새로 등록하려는 데이터를 localStorage에서 삭제(삭제하지 않으면 중복으로 남아있게 됨)
localStorage.removeItem(i);
localStorage.setItem(index, JSON.stringify(value)); //localStorage에 저장
}
}
}
window.location.reload();
}
HTML
<button onclick="updateCount(this,1)" class="plus">+</buttn><button onclick="updateCount(this,-1)" class="minus">-</button>
javascript
function updateCount(e, num){
//현재 고치려고 하는 데이터의 index값 찾기
let target = $(e).closest('tr').find('.index').text();
//해당 index의 데이터 불러오기
let cartItem = JSON.parse(localStorage.getItem(target))
//가져온 데이터에서 수량값이 현재 1이거나 그 이하이고 마이너스버튼을 눌렀을 경우엔 안내메시지 띄우고 중단
if(cartItem.count < 2 && num === -1){
alert("수량은 최소 1개입니다. 삭제를 원하실 경우 삭제버튼을 이용해주세요.");
return false;
}
//나머지는 그대로, 수량count과 가격price만 변경하여 기존 데이터를 삭제하고 다시 넣기
let index = Number(target);
let id = Number(index);
let menu = cartItem.menu;
//총 가격에서 개수를 나눠 단가를 계산한 뒤, num을 곱해 +인지 -인지 결정
let price = cartItem.price + num*(cartItem.price/cartItem.count);
let count = cartItem.count + num;
let img_url = cartItem.img_url;
let value = {
id: id,
menu: menu,
price: price,
count: count,
img_url: img_url
};
localStorage.setItem(index, JSON.stringify(value)); //localStorage에 저장(덮어쓰기)
window.location.reload();
}