저번시간에 짠 코드는 확장성이 부족한 것 같다.
셔츠사이즈를 95, 100 이라고 하드코딩해놓고 보여주기만 하기 때문이다.
실제 쇼핑몰이라면 셔츠 사이즈가 매일매일 바뀔 것인데
이럴 경우 서버에서 보낸 데이터 갯수에 맞게 <option> 태그를 생성해줘야 좋을듯하다.
select태그 & option태그
먼저 html을 생성하는 법을 알아보자.
<div>안에<p>태그를 생성하려면
index.html
<div id="test">
</div>
index.js
let pTag = document.createElement('p');
pTag.innerHTML = '안녕';
document.querySelector('#test').appendChild(pTag);
이러면 생성된. 개발자도구 까보면 div 안에 p태그가 생성되어있다.

document.createElement() 쓰면 html 자료를 하나 생성해준다.appendChild() 써서 아무데나 넣으면 html이 생성된다.
<div>안에<p>태그를 생성하려면 2
index.html
<div id="test">
</div>
index.js
let a = '<p>안녕</p>';
document.querySelector('#test').insertAdjacentHTML('beforeend', a);
이래도 생성된다.

html을 만든 다음insertAdjacentHTML() 안에 넣으면 된다.'beforeend' 이건 안쪽 맨 밑에 추가하라는 뜻이다. (싫으면 맘대로 변경가능)1번 방법은 코드가 너무 길고 복잡하기 때문에 특별한 이유 없으면 2번 방법을 사용한다.
(1번이 더 빠르게 동작하는데 0.0000x초 차이임)
먼저 html에 바지옵션을 추가하자
<form class="container my-5 form-group">
<p>상품선택</p>
<select class="form-select mt-2">
<option>모자</option>
<option>셔츠</option>
<option>바지</option>
</select>
<select class="form-select mt-2 form-hide">
<option>95</option>
<option>100</option>
</select>
</form>

바지옵션을 누르게 되면 28과 30 사이즈가 담긴 <select>가 떠야한다. 어떻게 코드를 짤 수 있을까?
html을 미리 만들어놨다가 보여줘도 되는데
실제 쇼핑몰의 경우 그렇게 만들어놓을 순 없다.
바지 사이즈가 매일 달라질 수 있기 때문이다.
실제 서비스는 매번 서버에서 데이터를 받아와서 "데이터 갯수만큼 <option> 생성해주세요~" 라고 코드를 짜놓는다.
그래서 우리도 이를 대비하기 위해 html을 미리 만들어놓지말고 자바스크립트로 html을 생성해보자.
방법은 위에서 배운 2번째 방법을 사용해보자
const formSelect = document.querySelectorAll(".form-select");
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
let template = "<option>28</option><option>30</option>";
formSelect[1].insertAdjacentHTML("beforeend", template);
}
}
코드실행이 어떤 순서로 이루어질까?
1. 유저가 바지를 선택하면
2. 먼저 둘 째<select>보여주세요
3. 둘 째<select>안에 비워주세요
4.html만들어서 둘 째<select>안에append해주세요

바지 눌렀다가 다시 셔츠 누르면 뭔가 이상해지는 문제도 해결해보기.
(셔츠눌렀을 때 둘 째<select>안에 있는 html도 조정해주면 될 것 같다.)
html 옵션 삭제
먼저 html에 있는 셔츠의 옵션
<option>95</option><option>100</option>이 코드를 삭제헤준다.<form class="container my-5 form-group"> <p>상품선택</p> <select class="form-select mt-2"> <option>모자</option> <option>셔츠</option> <option>바지</option> </select> <select class="form-select mt-2 form-hide"></select> </form>
바지 눌렀다가 다시 셔츠 누르면 뭔가 이상해지는 문제도 해결 & 모자 선택시 옵션 없애기
const formSelect = document.querySelectorAll(".form-select");
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
let template = "<option>95</option><option>100</option>";
formSelect[1].insertAdjacentHTML("beforeend", template);
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
let template = "<option>28</option><option>30</option>";
formSelect[1].insertAdjacentHTML("beforeend", template);
} else {
formSelect[1].classList.add("form-hide");
}
}

오늘은 서버에서 바지 사이즈 데이터 가져와서
그 갯수만큼 <option>을 생성해볼 것이다.
const formSelect = document.querySelectorAll(".form-select");
let pants = [28, 30, 32];
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
<무슨 코드 짜야할까?>
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
<무슨 코드 짜야할까?>
} else {
formSelect[1].classList.add("form-hide");
}
}
먼저 셔츠부분은 냅두고 바지부분에 대해서 코드를 만들어보자
맨 위에 pants 라는 변수를 하나 만들고 서버에서 보낸데이터라고 가정해보자.
pants 데이터 갯수만큼 <option>을 생성하고싶으면 어떻게 해야할까?
반복문 쓰면 될 것 같다.
const formSelect = document.querySelectorAll(".form-select");
let pants = [28, 30, 32];
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
<무슨 코드 짜야할까?>
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
for (let i = 0; i < pants.length; i++) {
let option = document.createElement("option");
option.value = pants[i];
option.textContent = pants[i];
formSelect[1].appendChild(option);
}
} else {
formSelect[1].classList.add("form-hide");
}
}
이런식으로 작성할 수 있을 것 같다.
한번 for문에 대해 해석해보자
코드해석
- 바지가 선택되었을 때
pant배열의 길이가i보다 작으면for문안에 있는 코드가 실행된다.<option>요소를 생성한 뒤option변수에 넣어준다.option.value와option.textContent를 사용하여<option>의 값을 설정한다.appendChild를 사용하여 빈select요소에 추가한다.
이렇게 for문이 완성되면 바지를 선택했을 때 pants로 부터 데이터를 잘 갖고 오는 것을 볼 수 있다.

근데 for문보다 더 쉬운 반복문이 있다. 그 반복문에 대해서 알아보자
배열을 순회해서 각 요소를 콜백 함수로 처리하기 위한 함수
쉽게말해 배열의 각 요소에 대해 주어진 콜백 함수를 적용해서 순서대로 한 번씩 실행한다.
한번 아래 예시를 살펴보자
let pants = [28, 30, 32];
pants.forEach(function(){
console.log('안녕')
});
이렇게 되면 콘솔에는 어떤게 표시될까?

안녕이 3번 반복되는 것을 볼 수 있다.
이로인해 알 수 있는 것은
pants 안의 데이터 갯수만큼
forEach 콜백함수 안에 있는 코드가 실행되는 것을 알수있다.
let pants = [28, 30, 32];
pants.forEach(function(a, i){
console.log(a, i)
});
콜백함수 안에 파라미터 2개까지 작명이 가능한데 (실은 3개까지 가능하다.)
첫 파라미터는 반복문 돌 때 마다 array 안에 있던 하나하나의 데이터가 되고
둘 째 파라미터는 반복문 돌 때 마다 0부터 1씩 증가하는 정수가 된다.
한번 콘솔에 a와 i 출력해보자

이제 위에서 배운 forEach를 통해 코드를 바꾸어보자
const formSelect = document.querySelectorAll(".form-select");
let pants = [28, 30, 32];
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
let template = "<option>95</option><option>100</option>";
formSelect[1].insertAdjacentHTML("beforeend", template);
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
pants.forEach(function (size) {
let optionTemplate = `<option>${size}</option>`;
formSelect[1].insertAdjacentHTML("beforeend", optionTemplate);
});
} else {
formSelect[1].classList.add("form-hide");
}
}
이제 pants 라는 서버에서 보낸 데이터가 바뀔 때 마다
거기에 맞게 <option>이 생성될 것 같다. 변화에 대응이 좋은 코드가 되었다!

나머지 셔츠에 대한 부분도 똑같이 만들어보자
const formSelect = document.querySelectorAll(".form-select");
let shirts = [95, 100, 105];
let pants = [28, 30, 32];
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
shirts.forEach(function (size) {
let optionTemplate = `<option>${size}</option>`;
formSelect[1].insertAdjacentHTML("beforeend", optionTemplate);
});
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
pants.forEach(function (size) {
let optionTemplate = `<option>${size}</option>`;
formSelect[1].insertAdjacentHTML("beforeend", optionTemplate);
});
} else {
formSelect[1].classList.add("form-hide");
}
}

셔츠도 마찬가지로 shirts 라는 서버에서 보낸 데이터가 바뀔 때 마다 거기에 맞게 <option>이 생성되도록 만들어주었다.
object 자료 갯수만큼 반복문을 돌리고 싶으면
let obj = { name : 'kim', age : 20 }
for (let keyTest in obj){
console.log('안녕')
}
for in 반복문 쓰면 된다.
for in 반복문에 대해서 잘 모르니 아래 사이트를 통해 이해하고 넘어가자
for in 반복문
그렇다면 콘솔창에 '안녕'이 몇번 출력될까?

2번이 출력되는 것을 볼 수 있다.
또 for in 반복문 쓰면 object 자료 안에 있는 key와 value를 다 출력해볼 수도 있다.
지금 keyTest라고 작명하는 부분은 반복문이 돌 때 마다 object자료 안에 있던 key값이 된다.
let obj = { name : 'kim', age : 20 }
for (let keyTest in obj){
console.log(keyTest)
}

출력해보면 진짜로 name, age 잘 나온다.
keyTest 말고 실제 자료인 value를 출력하고 싶으면
let obj = { name : 'kim', age : 20 }
for (let keyTest in obj){
console.log(obj[keyTest])
}
위와 같이 코드를 작성하면 value를 출력할 수 있다. 콘솔을 확인해보자

value값이 출력되는 것을 볼 수 있다.
원래 코드 복사붙여넣기용으로 쓰는게 for 반복문이라 했는데
array나 object 자료 전부 꺼내서 쓰고 싶을 때도 반복문을 쓰면 유용하다.
그래서
1. 코드복붙하고싶으면
2. array, object 자료 다 꺼내고 싶을 때
반복문 사용하면 유용하다!
함수 만드는 다른 문법이 있다. 특히 콜백함수만들 때 자주 쓰는 방법인데
let pants = [28, 30, 32];
pants.forEach(function(size){
console.log(size)
});
// 위 함수를 아래 arrow function으로 바꿀 수 있다.
pants.forEach((size) => {
console.log(size)
});
function 키워드 대신 => 화살표를 ( ) 우측에 부착해도 똑같이 함수만들 수 있다.
저걸 arrow function 이라고 한다.
pants.forEach( size => {
console.log(this)
});
arrow function은 파라미터가 하나면 () 소괄호 생략해도 괜찮다.
함수 중괄호 안에 return 한 줄 밖에 없으면 { } 중괄호와 return 동시에 생략해도 괜찮다.
그래서 간결하니 콜백함수에 자주 사용하는 사람들이 있다.
let 함수 = function(){ console.log('안녕') }
let 함수 = () => { console.log('안녕') }
참고로 함수 이렇게 만들어쓰는 사람도 있다.
이럴 때도 arrow function이 가끔 보인다.
그냥 함수와 arrow function의 기능차이는 하나가 있는데
함수 안에서 this를 써야할 경우
arrow function은 함수 안에서 this를 재정의해주지 않고 바깥에 있던 this를 그대로 사용한다.this를 써야하면 arrow function 쓰면 의도와 다르게 동작할 수도 있다.index.html
<!DOCTYPE html>
<html lang="en">
<head>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="./index.css" />
<title>Level3</title>
</head>
<body>
<!-- <div class="container mt-3">
<div class="card p-3">
<span class="product">상품명</span>
<span class="price">가격</span>
</div>
</div> -->
<form class="container my-5 form-group">
<p>상품선택</p>
<select class="form-select mt-2">
<option>모자</option>
<option>셔츠</option>
<option>바지</option>
</select>
<select class="form-select mt-2 form-hide"></select>
</form>
<script src="./index.js"></script>
</body>
</html>
index.js
// const product = document.querySelector(".product");
// const price = document.querySelector(".price");
// let car2 = { name: "소나타", price: [50000, 3000, 4000] };
// product.innerHTML = car2.name;
// price.innerHTML = car2.price[0];
const formSelect = document.querySelectorAll(".form-select");
let shirts = [95, 100, 105];
let pants = [28, 30, 32];
formSelect[0].addEventListener("input", handleSelect);
function handleSelect(e) {
let value = e.currentTarget.value;
if (value == "셔츠") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
shirts.forEach(function (size) {
let optionTemplate = `<option>${size}</option>`;
formSelect[1].insertAdjacentHTML("beforeend", optionTemplate);
});
} else if (value == "바지") {
formSelect[1].classList.remove("form-hide");
formSelect[1].innerHTML = "";
pants.forEach(function (size) {
let optionTemplate = `<option>${size}</option>`;
formSelect[1].insertAdjacentHTML("beforeend", optionTemplate);
});
} else {
formSelect[1].classList.add("form-hide");
}
}
index.css
.form-hide {
display: none;
}