- [개발자의품격][부트캠프][1기][16차시] 부트스트랩 #2 | 조회, 삭제2022년 03월 02일 09시 52분 44초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
부트스트랩 #2
1. Starter template 가져오기
https://getbootstrap.com/docs/5.1/getting-started/introduction/#starter-template
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <h1>Hello, world!</h1> <!-- Optional JavaScript; choose one of the two! --> <!-- Option 1: Bootstrap Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <!-- Option 2: Separate Popper and Bootstrap JS --> <!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script> --> </body> </html>
2. 네비게이션바 가져오기
https://getbootstrap.com/docs/5.1/examples/carousel/
<header> <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <div class="container-fluid"> <a class="navbar-brand" href="#">Carousel</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarCollapse"> <ul class="navbar-nav me-auto mb-2 mb-md-0"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="#">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Link</a> </li> <li class="nav-item"> <a class="nav-link disabled">Disabled</a> </li> </ul> <form class="d-flex"> <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success" type="submit">Search</button> </form> </div> </div> </nav> </header>
3. Inline forms 적용
https://getbootstrap.com/docs/5.1/forms/layout/#inline-forms
<main></main> 태그 안에 Inline forms을 넣는다.
<form class="row row-cols-lg-auto g-3 align-items-center"> <div class="col-12"> <label class="visually-hidden" for="inlineFormInputGroupUsername">Username</label> <div class="input-group"> <div class="input-group-text">@</div> <input type="text" class="form-control" id="inlineFormInputGroupUsername" placeholder="Username"> </div> </div> <div class="col-12"> <label class="visually-hidden" for="inlineFormSelectPref">Preference</label> <select class="form-select" id="inlineFormSelectPref"> <option selected>Choose...</option> <option value="1">One</option> <option value="2">Two</option> <option value="3">Three</option> </select> </div> <div class="col-12"> <div class="form-check"> <input class="form-check-input" type="checkbox" id="inlineFormCheck"> <label class="form-check-label" for="inlineFormCheck"> Remember me </label> </div> </div> <div class="col-12"> <button type="submit" class="btn btn-primary">Submit</button> </div> </form>
4. Inline forms 보이게하기
네비게이션바 뒤에 숨어있는 Inlin forms의 위치를 변경하여 보이게한다.
4.1 위쪽 간격 조정
<style> main { margin-top: 70px; } </style>
4.2 왼쪽 간격 조정
<div class="container"> <!-- Inline forms 넣기 --> </div>
5. Inline forms 구성 변경
셀렉트 박스에 라벨이 보이지 않으나 코드가 존재한다. label class="visually-hidden"을 주어 사용자 눈에는 보이지 않게 처리하고 ARIA를 만족시킨다.
<form>을 쓰지 않으므로 <div>로 변경하고 셀렉트 박스 위치 변경 및 수정, 버튼 수정 및 추가, 간격 조정 등을 해주었다.
<div class="row row-cols-lg-auto g-2 align-items-center"> <div class="col-12"> <label class="visually-hidden" for="gender" >성별선택</label > <select class="form-select" id="gender"> <option value="" selected>전체</option> <option value="male">남자</option> <option value="female">여자</option> </select> </div> <div class="col-12"> <label class="visually-hidden" for="name" >Username</label > <!-- <div class="input-group"> <div class="input-group-text">@</div> --> <input type="search" class="form-control" id="name" placeholder="Username" /> <!-- </div> --> </div> <!-- <div class="col-12"> <div class="form-check"> <input class="form-check-input" type="checkbox" id="inlineFormCheck" /> <label class="form-check-label" for="inlineFormCheck"> Remember me </label> </div> </div> --> <div class="col-12"> <button class="btn btn-primary">조회</button> <button class="btn btn-success">생성</button> <button class="btn btn-danger">삭제</button> </div> </div>
6. table 생성
Inline forms을 감싸고 있는 </div> 아래에 table을 추가한다. class="form-check-input"을 주어 체크박스 디자인 개선하였다.
<table class="table table-bordered table-striped mt-2"> <thead> <tr> <th> <!-- class="form-check-input"을 주어 체크박스 디자인 개선 --> <input type="checkbox" id="chks" class="form-check-input" onchange="checkAll()" /> </th> <th>Name</th> <th>Company</th> <th>Gender</th> <th>Email</th> <th>Phone</th> <th>Addres</th> </tr> </thead> <tbody id="tbBody"></tbody> </table>
7. JavaScript 함수 추가
<script> async function doSearch() { const gender = document.querySelector("#gender").value; const name = document.querySelector("#name").value; let resource = "http://localhost:3000/customers"; if (gender === "") { if (name !== "") { resource = `http://localhost:3000/customers?name_like=${name}`; } } else { if (name === "") { resource = `http://localhost:3000/customers?gender=${gender}`; } else { resource = `http://localhost:3000/customers?gender=${gender}&name_like=${name}`; } } // if (gender !== "") { // resource = `http://localhost:3000/customers?gender=${gender}`; // } const res = await fetch(resource); const resJson = await res.json(); console.log(resJson); renderTable(resJson); } function renderTable(data) { const h = []; for (const item of data) { h.push("<tr>"); h.push( `<td><input type="checkbox" class="form-check-input" value="${item.id}" name="chk" onchange="isChecked();" /></td>` // class="form-check-input"으로 체크박스 디자인 개선 ); h.push(`<td>${item.name}</td>`); h.push(`<td>${item.company}</td>`); h.push(`<td>${item.gender}</td>`); h.push(`<td>${item.email}</td>`); h.push(`<td>${item.phone}</td>`); h.push(`<td>${item.address}</td>`); h.push("</tr>"); } document.querySelector("#tbBody").innerHTML = h.join(""); } async function doDelete() { const chks = document.querySelectorAll("[name=chk]:checked"); if (chks.length > 0) { if (confirm("정말 삭제하시겠습니까?")) { for (const chk of chks) { await fetch(`http://localhost:3000/customers/${chk.value}`, { method: "DELETE", }); } alert("데이터가 정상작으로 삭제 되었습니다."); } } else { alert("삭제할 아이템을 선택하세요."); } } function checkAll() { const checkValue = document.querySelector("#chks").checked; const chks = document.querySelectorAll("[name=chk]"); for (const chk of chks) { chk.checked = checkValue; } isChecked(); } function isChecked() { const chks = document.querySelectorAll("[name=chk]:checked"); if (chks.length > 0) { document.querySelector("#btnDelete").disabled = false; } else { document.querySelector("#btnDelete").disabled = true; } } function goToCreate() { document.location.href = "dom_create.html"; } function checkEnter(e) { // console.log(e); if (e.keyCode === 13) { doSearch(); } } </script>
조회/삭제 버튼에 onclick 이벤트를 적용한다.
<button class="btn btn-primary" onclick="doSearch();">조회</button> <button class="btn btn-success">생성</button> <button class="btn btn-danger" onclick="doDelete();">삭제</button>
8. 삭제기능 sweetalert 적용
8.1 sweetalert 스크립트 추가
https://sweetalert2.github.io/#download 에서 CDN을 복사해 추가한다. sweetalert을 쓸수 있는 상태가 된다.
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
8.2 sweetalert 추가
A confirm dialog, with a function attached to the "Confirm"-button의 코드를 가져온다.
Swal.fire({ title: 'Are you sure?', text: "You won't be able to revert this!", icon: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: 'Yes, delete it!' }).then((result) => { if (result.isConfirmed) { Swal.fire( 'Deleted!', 'Your file has been deleted.', 'success' ) } })
8.3 doDelete 함수에 sweetalert 적용
async function doDelete() { const chks = document.querySelectorAll("[name=chk]:checked"); if (chks.length > 0) { Swal.fire({ title: "정말 삭제하시겠습니까?", text: "삭제된 데이터는 복원되지 않습니다!", icon: "warning", showCancelButton: true, confirmButtonColor: "#3085d6", cancelButtonColor: "#d33", confirmButtonText: "삭제", cancelButtonText: "취소", }).then(async (result) => { if (result.isConfirmed) { for (const chk of chks) { await fetch(`http://localhost:3000/customers/${chks[0].value}`, { method: "DELETE", }); } Swal.fire( "삭제 성공!", "데이터가 정상적으로 삭제 되었습니다.", "success" ); } }); } else { Swal.fire("삭제할 아이템을 선택하세요."); } }
9. 삭제버튼에 효과 적용
삭제 항목이 선택된 경우에만 버튼이 활성화 되도록 한다.
<button class="btn btn-danger" id="btnDelete" onclick="doDelete();" disabled> 삭제 </button>
10. 최종 코드
네비게이션바의 이름을 "부트스트랩 실습"으로 변경해주었다.
<!DOCTYPE html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" /> <title>Hello, world!</title> <!-- 4. Inline forms 보이게하기 - 위쪽 간격 조정 --> <style> main { margin-top: 70px; } </style> </head> <body> <!-- 2. 네비게이션바 가져오기 https://getbootstrap.com/docs/5.1/examples/carousel/ --> <header> <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <div class="container-fluid"> <!-- 10. 네비게이션바 이름 변경 --> <a class="navbar-brand" href="#">부트스트랩 실습</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarCollapse"> <ul class="navbar-nav me-auto mb-2 mb-md-0"> <li class="nav-item"> <a class="nav-link active" aria-current="page" href="#">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="#">Link</a> </li> <li class="nav-item"> <a class="nav-link disabled">Disabled</a> </li> </ul> <form class="d-flex"> <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" /> <button class="btn btn-outline-success" type="submit"> Search </button> </form> </div> </div> </nav> </header> <!-- 3. Inline forms 적용 https://getbootstrap.com/docs/5.1/forms/layout/#inline-forms --> <main> <!-- 4. Inline forms 보이게하기 - 왼쪽 간격 조정 --> <div class="container"> <!-- 5. Inline forms 구성 변경 --> <div class="row row-cols-lg-auto g-2 align-items-center"> <div class="col-12"> <label class="visually-hidden" for="gender">성별선택</label> <select class="form-select" id="gender"> <option value="" selected>전체</option> <option value="male">남자</option> <option value="female">여자</option> </select> </div> <div class="col-12"> <label class="visually-hidden" for="name">Username</label> <input type="search" class="form-control" id="name" placeholder="Username" /> </div> <div class="col-12"> <!-- 7. JavaScript 함수 추가 - 조회/삭제 버튼에 onclick 이벤트를 적용 --> <button class="btn btn-primary" onclick="doSearch();">조회</button> <button class="btn btn-success">생성</button> <!-- 9. 삭제버튼에 효과 적용 --> <button class="btn btn-danger" id="btnDelete" onclick="doDelete();" disabled > 삭제 </button> </div> </div> <!-- 6. table 생성 --> <table class="table table-bordered table-striped mt-2"> <thead> <tr> <th> <!-- class="form-check-input"을 주어 체크박스 디자인 개선 --> <input type="checkbox" id="chks" class="form-check-input" onchange="checkAll()" /> </th> <th>Name</th> <th>Company</th> <th>Gender</th> <th>Email</th> <th>Phone</th> <th>Addres</th> </tr> </thead> <tbody id="tbBody"></tbody> </table> </div> </main> <!-- Optional JavaScript; choose one of the two! --> <!-- Option 1: Bootstrap Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous" ></script> <!-- Option 2: Separate Popper and Bootstrap JS --> <!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script> --> <!-- 8. 삭제기능 sweetalert 적용 --> <!-- https://sweetalert2.github.io/#download 에서 CDN을 복사해 추가한다. --> <script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script> <!-- 7. JavaScript 함수 추가 --> <script> async function doSearch() { const gender = document.querySelector("#gender").value; const name = document.querySelector("#name").value; let resource = "http://localhost:3000/customers"; if (gender === "") { if (name !== "") { resource = `http://localhost:3000/customers?name_like=${name}`; } } else { if (name === "") { resource = `http://localhost:3000/customers?gender=${gender}`; } else { resource = `http://localhost:3000/customers?gender=${gender}&name_like=${name}`; } } const res = await fetch(resource); const resJson = await res.json(); console.log(resJson); renderTable(resJson); } function renderTable(data) { const h = []; for (const item of data) { h.push("<tr>"); h.push( `<td><input type="checkbox" class="form-check-input" value="${item.id}" name="chk" onchange="isChecked();" /></td>` // class="form-check-input"으로 체크박스 디자인 개선 ); h.push(`<td>${item.name}</td>`); h.push(`<td>${item.company}</td>`); h.push(`<td>${item.gender}</td>`); h.push(`<td>${item.email}</td>`); h.push(`<td>${item.phone}</td>`); h.push(`<td>${item.address}</td>`); h.push("</tr>"); } document.querySelector("#tbBody").innerHTML = h.join(""); } // 8. 삭제기능 sweetalert 적용 async function doDelete() { const chks = document.querySelectorAll("[name=chk]:checked"); if (chks.length > 0) { Swal.fire({ title: "정말 삭제하시겠습니까?", text: "삭제된 데이터는 복원되지 않습니다!", icon: "warning", showCancelButton: true, confirmButtonColor: "#3085d6", cancelButtonColor: "#d33", confirmButtonText: "삭제", cancelButtonText: "취소", }).then(async (result) => { if (result.isConfirmed) { for (const chk of chks) { await fetch( `http://localhost:3000/customers/${chks[0].value}`, { method: "DELETE", } ); } Swal.fire( "삭제 성공!", "데이터가 정상적으로 삭제 되었습니다.", "success" ); } }); } else { Swal.fire("삭제할 아이템을 선택하세요."); } } function checkAll() { const checkValue = document.querySelector("#chks").checked; const chks = document.querySelectorAll("[name=chk]"); for (const chk of chks) { chk.checked = checkValue; } isChecked(); } function isChecked() { const chks = document.querySelectorAll("[name=chk]:checked"); if (chks.length > 0) { document.querySelector("#btnDelete").disabled = false; } else { document.querySelector("#btnDelete").disabled = true; } } function goToCreate() { document.location.href = "dom_create.html"; } function checkEnter(e) { // console.log(e); if (e.keyCode === 13) { doSearch(); } } </script> </body> </html>
728x90반응형'영광의 시대! > 2022 개발자의 품격 부트캠프 1기' 카테고리의 다른 글
[개발자의품격][부트캠프][1기][16차시] 부트스트랩 #4 | 모달 (0) 2022.03.02 [개발자의품격][부트캠프][1기][16차시] 부트스트랩 #3 | 생성 (0) 2022.03.02 [개발자의품격][부트캠프][1기][15차시] 부트스트랩 #1 (0) 2022.03.01 [개발자의품격][부트캠프][1기][15차시] JavaScript 주요 포인트 #22 | 이벤트 (0) 2022.03.01 [개발자의품격][부트캠프][1기][14차시] JavaScript 주요 포인트 #21 | 데이터 그리드 - 정렬, 필터, 페이징 (0) 2022.02.28 다음글이 없습니다.이전글이 없습니다.댓글