Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[14기 양아름] step1 돔 조작과 이벤트 핸들링으로 메뉴 관리하기 #268

Open
wants to merge 2 commits into
base: areumsheep
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 36 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@

<br/>

## 🏃 잘살아보세

| 성함 | 깃허브 |
| ----------------------------------------- | ------------------------------- |
| [양아름](https://github.com/areumsheep) | https://github.com/areumsheep |
| [김가람](https://github.com/dev-riverkim) | https://github.com/dev-riverkim |
| [신윤선](https://github.com/jnny1017) | https://github.com/jnny1017 |
| [유원영](https://github.com/yooveloper) | https://github.com/yooveloper |
| [김슬기](https://github.com/sgsg9447) | https://github.com/sgsg9447 |

<br/>

## 🔥 Projects!

<p align="middle">
Expand All @@ -43,28 +55,28 @@

## 🎯 step1 요구사항 - 돔 조작과 이벤트 핸들링으로 메뉴 관리하기

- [ ] 에스프레소 메뉴에 새로운 메뉴를 확인 버튼 또는 엔터키 입력으로 추가한다.
- [ ] 메뉴가 추가되고 나면, input은 빈 값으로 초기화한다.
- [ ] 사용자 입력값이 빈 값이라면 추가되지 않는다.
- [ ] 메뉴의 수정 버튼을 눌러 메뉴 이름 수정할 수 있다.
- [ ] 메뉴 수정시 브라우저에서 제공하는 `prompt` 인터페이스를 활용한다.
- [ ] 메뉴 삭제 버튼을 이용하여 메뉴 삭제할 수 있다.
- [ ] 메뉴 삭제시 브라우저에서 제공하는 `confirm` 인터페이스를 활용한다.
- [ ] 총 메뉴 갯수를 count하여 상단에 보여준다.
- [x] 에스프레소 메뉴에 새로운 메뉴를 확인 버튼 또는 엔터키 입력으로 추가한다.
- [x] 메뉴가 추가되고 나면, input은 빈 값으로 초기화한다.
- [x] 사용자 입력값이 빈 값이라면 추가되지 않는다.
- [x] 메뉴의 수정 버튼을 눌러 메뉴 이름 수정할 수 있다.
- [x] 메뉴 수정시 브라우저에서 제공하는 `prompt` 인터페이스를 활용한다.
- [x] 메뉴 삭제 버튼을 이용하여 메뉴 삭제할 수 있다.
- [x] 메뉴 삭제시 브라우저에서 제공하는 `confirm` 인터페이스를 활용한다.
- [x] 총 메뉴 갯수를 count하여 상단에 보여준다.
- 추가되는 메뉴의 아래 마크업은 `<ul id="espresso-menu-list" class="mt-3 pl-0"></ul>` 안에 삽입해야 한다.

```js
<li class="menu-list-item d-flex items-center py-2">
<span class="w-100 pl-2 menu-name">${name}</span>
<li class='menu-list-item d-flex items-center py-2'>
<span class='w-100 pl-2 menu-name'>${name}</span>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button"
type='button'
class='bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button'
>
수정
</button>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm menu-remove-button"
type='button'
class='bg-gray-50 text-gray-500 text-sm menu-remove-button'
>
삭제
</button>
Expand All @@ -80,23 +92,23 @@
- 품절 상태 메뉴의 마크업

```js
<li class="menu-list-item d-flex items-center py-2">
<span class="w-100 pl-2 menu-name sold-out">${name}</span>
<li class='menu-list-item d-flex items-center py-2'>
<span class='w-100 pl-2 menu-name sold-out'>${name}</span>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm mr-1 menu-sold-out-button"
type='button'
class='bg-gray-50 text-gray-500 text-sm mr-1 menu-sold-out-button'
>
품절
</button>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button"
type='button'
class='bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button'
>
수정
</button>
<button
type="button"
class="bg-gray-50 text-gray-500 text-sm menu-remove-button"
type='button'
class='bg-gray-50 text-gray-500 text-sm menu-remove-button'
>
삭제
</button>
Expand Down Expand Up @@ -147,8 +159,8 @@
{
response: [
{
id: "string",
name: "string",
id: 'string',
name: 'string',
isSoldOut: Boolean,
},
];
Expand Down
160 changes: 80 additions & 80 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,89 +1,89 @@
<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="UTF-8" />
<title>문벅스 메뉴</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="src/images/favicon.ico" />
<link rel="icon" href="src/images/favicon.png" />
<link rel="stylesheet" href="src/css/index.css" />
</head>
<body>
<div id="app" class="px-4">
<div class="d-flex justify-center mt-5 w-100">
<div class="w-100">
<header class="my-4">
<a href="/" class="text-black">
<h1 class="text-center font-bold">🌝 문벅스 메뉴 관리</h1>
</a>
<nav class="d-flex justify-center flex-wrap">
<button
data-category-name="espresso"
class="cafe-category-name btn bg-white shadow mx-1"
>
☕ 에스프레소
</button>
<button
data-category-name="frappuccino"
class="cafe-category-name btn bg-white shadow mx-1"
>
🥤 프라푸치노
</button>
<button
data-category-name="blended"
class="cafe-category-name btn bg-white shadow mx-1"
>
🍹 블렌디드
</button>
<button
data-category-name="teavana"
class="cafe-category-name btn bg-white shadow mx-1"
>
🫖 티바나
</button>
<button
data-category-name="desert"
class="cafe-category-name btn bg-white shadow mx-1"
>
🍰 디저트
</button>
</nav>
</header>
<main class="mt-10 d-flex justify-center">
<div class="wrapper bg-white p-10">
<div class="heading d-flex justify-between">
<h2 class="mt-1">☕ 에스프레소 메뉴 관리</h2>
<span class="mr-2 mt-4 menu-count">총 0개</span>
</div>
<form id="espresso-menu-form">
<div class="d-flex w-100">
<label for="espresso-menu-name" class="input-label" hidden>
에스프레소 메뉴 이름
</label>
<input
type="text"
id="espresso-menu-name"
name="espressoMenuName"
class="input-field"
placeholder="에스프레소 메뉴 이름"
autocomplete="off"
/>
<head>
<meta charset="UTF-8" />
<title>문벅스 메뉴</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="src/images/favicon.ico" />
<link rel="icon" href="src/images/favicon.png" />
<link rel="stylesheet" href="src/css/index.css" />
</head>
<body>
<div id="app" class="px-4">
<div class="d-flex justify-center mt-5 w-100">
<div class="w-100">
<header class="my-4">
<a href="/" class="text-black">
<h1 class="text-center font-bold">🌝 문벅스 메뉴 관리</h1>
</a>
<nav class="d-flex justify-center flex-wrap">
<button
type="button"
name="submit"
id="espresso-menu-submit-button"
class="input-submit bg-green-600 ml-2"
data-category-name="espresso"
class="cafe-category-name btn bg-white shadow mx-1"
>
확인
☕ 에스프레소
</button>
<button
data-category-name="frappuccino"
class="cafe-category-name btn bg-white shadow mx-1"
>
🥤 프라푸치노
</button>
<button
data-category-name="blended"
class="cafe-category-name btn bg-white shadow mx-1"
>
🍹 블렌디드
</button>
<button
data-category-name="teavana"
class="cafe-category-name btn bg-white shadow mx-1"
>
🫖 티바나
</button>
<button
data-category-name="desert"
class="cafe-category-name btn bg-white shadow mx-1"
>
🍰 디저트
</button>
</nav>
</header>
<main class="mt-10 d-flex justify-center">
<div class="wrapper bg-white p-10">
<div class="heading d-flex justify-between">
<h2 class="mt-1">☕ 에스프레소 메뉴 관리</h2>
<span class="mr-2 mt-4 menu-count">총 0개</span>
</div>
<form id="espresso-menu-form">
<div class="d-flex w-100">
<label for="espresso-menu-name" class="input-label" hidden>
에스프레소 메뉴 이름
</label>
<input
type="text"
id="espresso-menu-name"
name="espressoMenuName"
class="input-field"
placeholder="에스프레소 메뉴 이름"
autocomplete="off"
/>
<button
type="submit"
name="submit"
id="espresso-menu-submit-button"
class="input-submit bg-green-600 ml-2"
>
확인
</button>
</div>
</form>
<ul id="espresso-menu-list" class="mt-3 pl-0"></ul>
</div>
</form>
<ul id="espresso-menu-list" class="mt-3 pl-0"></ul>
</main>
</div>
</main>
</div>
</div>
</div>
</div>
<script type="module" src="./src/js/index.js"></script>
</body>
<script type="module" src="./src/js/index.js" defer></script>
</body>
</html>
61 changes: 61 additions & 0 deletions src/js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { $ } from './utils/dom.js';

let orderedMenuCount = 0;
const espressoMenuCount = $('.menu-count');
const espressoMenuForm = $('#espresso-menu-form');
const espressoMenuInput = $('#espresso-menu-name');
const espressoMenuList = $('#espresso-menu-list');
Comment on lines +3 to +7

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용되는 변수들을 모아두니 보기 편하네요! 😀


const updateEspressoMenuCount = (number) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, -1 를 인자로 넘겨서 처리 하셨군요!
menu list의 length를 활용하는 방법도 고려해보면 좋을것 같아요 !

orderedMenuCount += number;
espressoMenuCount.innerText = `총 ${orderedMenuCount}개`;
};

espressoMenuForm.addEventListener('submit', (event) => {
event.preventDefault();
const menuName = espressoMenuInput.value;

if (menuName) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

early return 해주면 뒤 코드의 흐름을 보기 더 쉬울 것 같아요~!

const content = `
<li class="menu-list-item d-flex items-center py-2">
<span class="w-100 pl-2 menu-name">${menuName}</span>
<button
type="button"
data-action="edit"
class="bg-gray-50 text-gray-500 text-sm mr-1 menu-edit-button"
>
수정
</button>
<button
type="button"
data-action="delete"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 name attribute 를 추가하여 이벤트를 분기했는데 data-action을 사용하셨네요 !👍

class="bg-gray-50 text-gray-500 text-sm menu-remove-button"
>
삭제
</button>
</li>
`;

espressoMenuList.insertAdjacentHTML('beforeend', content);
espressoMenuForm.reset();
updateEspressoMenuCount(+1);
}
});

espressoMenuList.addEventListener('click', (event) => {
const currentTarget = event.target;
switch (currentTarget?.dataset.action) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

옵셔널체이닝 좋네요! 👍 data로 이벤트를 분기 하는 것 도 좋은 것 같아요!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dataset 을 사용해서 switch 쓰도록 한 방식 좋네요! 저도 사용해봐야겠네용 ㅎㅎ

case 'edit':
const newMenuName = prompt('메뉴명을 수정하세요.');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 메뉴 이름이 비어 있을 때도 체크해주면 좋을 것 같아요~!

currentTarget.previousElementSibling.innerText = newMenuName;
break;
case 'delete':
const deleteFlag = confirm('정말 삭제하시겠습니까?');
if (deleteFlag) {
const deleteMenu = currentTarget.closest('.menu-list-item');
deleteMenu.remove();
}
updateEspressoMenuCount(-1);
Comment on lines +54 to +58

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (deleteFlag) {
const deleteMenu = currentTarget.closest('.menu-list-item');
deleteMenu.remove();
}
updateEspressoMenuCount(-1);
if (!deleteFlag) {
return;
}
const deleteMenu = currentTarget.closest('.menu-list-item');
deleteMenu.remove();
updateEspressoMenuCount(-1);

지금은 취소를 눌러도 updateEspressoMenuCount가 호출되네요 early return 이 이런 오류를 예방하기 좋은 것 같아요! 😀

break;
}
});
5 changes: 5 additions & 0 deletions src/js/utils/dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function $(selector) {
const element = document.querySelector(selector);
if (element === null) throw new Error('element is null');
Copy link

@dhrod0325 dhrod0325 Jul 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selector 이름을 만약에 잘못 입력 했을 때 예외처리를 안 해주게 되면 다음 스크립트가 동작을 안하게 되겠네요.!
엄격하게 체크하려고 의도 하신 건지 궁금해요~!😮

return element;
}