2차 공부/TIL

24.06.17 한식 메뉴 렌더링하기

공대탈출 2024. 6. 17. 15:54

 

const menuItems = [
    { name: '비빔밥', description: '밥 위에 나물, 고기, 고추장 등을 얹고 비벼 먹는 한국 요리' },
    { name: '김치찌개', description: '김치와 돼지고기 등을 넣고 끓인 한국의 찌개 요리' },
    { name: '불고기', description: '양념한 고기를 구워서 먹는 한국 요리' },
    { name: '떡볶이', description: '떡과 어묵을 고추장 양념에 볶아 만든 한국의 간식' },
    { name: '잡채', description: '당면과 여러 채소, 고기를 볶아 만든 한국 요리' }
];

주어진 문제는 다음과 같다.

menuItems 배열이 주어질 때, 각 요소의 description에 '고기'가 포함되는 음식만 위의 그림처럼 화면에 보이도록 하면 되는 것 이다.


먼저 틀을 만들었다.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>한식 메뉴 렌더링 하기</title>
        <style>
            .foodList {
                margin: 30px auto;
                padding: 10px;
                width: 500px;
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
            }
            .food {
                display: flex;
                flex-direction: column;
                justify-self: center;
                align-items: center;
                padding: 15px;
                border: 1px solid black;
                border-radius: 10px;
                margin: 5px auto;
            }
            .food > h2 {
                margin: 5px auto;
            }
        </style>
    </head>
    <body>
        <div class="foodList" id="foodList">
            <h1>한식 메뉴</h1>
            <div class="food">
                <h2>비빔밥</h2>
                <p>밥 위에 나물, 고기, 고추장 등을 얹고 비벼 먹는 한국 요리</p>
            </div>
        </div>
    </body>
</html>

각 메뉴를 모을 한식메뉴 탭과 각 메뉴가 표현될 스타일을 작성하였다.

 


다음으로 각 메뉴의 '고기'를 판별하고, 화면에 표시하기 위한 script를 작성하였다.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>한식 메뉴 렌더링 하기</title>
        <style>
            .foodList {
                margin: 30px auto;
                padding: 10px;
                width: 500px;
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
            }
            .food {
                display: flex;
                flex-direction: column;
                justify-self: center;
                align-items: center;
                padding: 15px;
                border: 1px solid black;
                border-radius: 10px;
                margin: 5px auto;
            }
            .food > h2 {
                margin: 5px auto;
            }
        </style>
        <script>
            const menuItems = [
                { name: '비빔밥', description: '밥 위에 나물, 고기, 고추장 등을 얹고 비벼 먹는 한국 요리' },
                { name: '김치찌개', description: '김치와 돼지고기 등을 넣고 끓인 한국의 찌개 요리' },
                { name: '불고기', description: '양념한 고기를 구워서 먹는 한국 요리' },
                { name: '떡볶이', description: '떡과 어묵을 고추장 양념에 볶아 만든 한국의 간식' },
                { name: '잡채', description: '당면과 여러 채소, 고기를 볶아 만든 한국 요리' },
            ];
            let target = document.querySelector('#foodList');
            target.innerHTML = menuItems
                .map((x) => {
                    if (x['description'].includes('고기')) {
                        return `<div class="food">
                        <h2>${x.name}</h2>
                        <p>${x.description}</p>
                        </div>`;
                    }
                })
                .join('');
        </script>
    </head>
    <body>
        <div class="foodList" id="foodList">
            <h1>한식 메뉴</h1>
            <div class="food">
                <h2>비빔밥</h2>
                <p>밥 위에 나물, 고기, 고추장 등을 얹고 비벼 먹는 한국 요리</p>
            </div>
        </div>
    </body>
</html>

 

그런데 오류가 발생하였다.

innerHTML에 대한 문제였는데, 문제는 다음과 같았다.

코드를 읽어들일때, script를 먼저 읽고 body태그로 가는데, script에서 body에 만들어져있는 foodList태그를 찾으려다보니 생성되어있지 않은 상태여서 생기는 오류였다.

 

따라서 페이지가 로드된 후 해당 부분이 작동되도록 바꾸어야했다.


<script>
    const menuItems = [
        { name: '비빔밥', description: '밥 위에 나물, 고기, 고추장 등을 얹고 비벼 먹는 한국 요리' },
        { name: '김치찌개', description: '김치와 돼지고기 등을 넣고 끓인 한국의 찌개 요리' },
        { name: '불고기', description: '양념한 고기를 구워서 먹는 한국 요리' },
        { name: '떡볶이', description: '떡과 어묵을 고추장 양념에 볶아 만든 한국의 간식' },
        { name: '잡채', description: '당면과 여러 채소, 고기를 볶아 만든 한국 요리' },
    ];
    window.addEventListener('DOMContentLoaded', () => {
        let target = document.querySelector('#foodList');
        target.innerHTML = menuItems
            .map((x) => {
                if (x['description'].includes('고기')) {
                    return `<div class="food">
                <h2>${x.name}</h2>
                <p>${x.description}</p>
                </div>`;
                }
            })
            .join('');
    });
</script>
<body>
    <div class="foodList" id="foodList">
        <h1>한식 메뉴</h1>
        <div class="food">
            <h2>비빔밥</h2>
            <p>밥 위에 나물, 고기, 고추장 등을 얹고 비벼 먹는 한국 요리</p>
        </div>
    </div>
</body>

 

간단히 보이기 위해 스크립트와 바디만 남겨두었다.

window.addEventListener를 사용하여 DOMContentLoaded일 때 뒤 함수를 실행하도록 하였다.

화면이 완전히 로드되면 foodList를 선택하고 해당 부분에 menuItems배열을 검사하는데

고기가 description에 포함되어있다면 알맞은 태그에 메뉴이름과 메뉴설명을 넣어 추가하는 방식을 택하였다.

 

완성본


에러가 발생했을 때 백틱 사용에 문제가 있는건지 왜 오류가 발생하는건지 코드를 보며 생각했지만

스크립트와 바디를 읽어오는 순서를 생각하지 못하여 고치지 못하였다.

그리하여 검색을 통해 해당 문제가 특정 id값을 가져오지 못하는 문제임을 알게되었고, 그제서야 script와 body태그를 읽어들이는 순서가 생각나 해당부분을 고칠 수 있었다.

 

기본적인 부분에서 실수를 하지 않으려면 연습을 해보아야 할 것 같다.

 


 

 

페이지 로드 후 실행하기 (window.onload, document.ready) / document.ready를 순수자바스크립트로! (DOMContentLo

📖 목차 스크립트를 위쪽에서 불러오면 요소를 찾지 못하는 오류를, 아래쪽에서 불러오면 느린 로딩속도 등의 이유로 우리는 스크립트 내에서 페이지로드 후 불러오는 함수를 사용하곤 한다.

mesonia.tistory.com

 

 

[JS] (err) TypeError: Cannot set properties of null (setting 'innerHTML')

오류 발생 ?원인 html 태그에 오타 혹은 누락이 있음조치웹문서가 load 된 후에 script가 작동하는지 ? 순서를 확인합니다.참고문서

velog.io