Dandy Now!
  • [개발자의품격][부트캠프][1기][16차시] 부트스트랩 #4 | 모달
    2022년 03월 02일 17시 30분 28초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    부트스트랩 #4

    https://getbootstrap.com/

     

    1.  Static backdrop 모달 가져오기

    1.1 Static backdrop 적용

    https://getbootstrap.com/docs/5.1/components/modal/#static-backdrop

    <!-- Modal -->
    <div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            ...
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
            <button type="button" class="btn btn-primary">Understood</button>
          </div>
        </div>
      </div>
    </div>

     

    1.2 Modal - Passing options

    https://getbootstrap.com/docs/5.1/components/modal/#passing-options

    모달을 띄우거나 숨긴다.

    var myModal = new bootstrap.Modal(document.getElementById('myModal'), {
      keyboard: false
    })

     

    1.3 id="customerModal" 설정

     

    2. 최종 코드

    <!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>
        <style>
          main {
            margin-top: 70px;
          }
        </style>
      </head>
      <body>
        <header>
          <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
            <div class="container-fluid">
              <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>
        <main>
          <div class="container">
            <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="searchName">Username</label>
    
                <input
                  type="search"
                  class="form-control"
                  id="searchName"
                  placeholder="Name"
                />
              </div>
              <div class="col-12">
                <button class="btn btn-primary" onclick="doSearch();">조회</button>
                <button class="btn btn-success">생성</button>
                <button
                  class="btn btn-danger"
                  id="btnDelete"
                  onclick="doDelete();"
                  disabled
                >
                  삭제
                </button>
              </div>
            </div>
            <table class="table table-bordered table-striped mt-2">
              <thead>
                <tr>
                  <th>
                    <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>
        <!-- 1.1 Static backdrop 적용(https://getbootstrap.com/docs/5.1/components/modal/#static-backdrop) -->
        <!-- 1.3 id="customerModal" 설정  -->
        <div
          class="modal fade"
          id="customerModal"
          data-bs-backdrop="static"
          data-bs-keyboard="false"
          tabindex="-1"
          aria-labelledby="staticBackdropLabel"
          aria-hidden="true"
        >
          <div class="modal-dialog">
            <div class="modal-content">
              <div class="modal-header">
                <h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
                <button
                  type="button"
                  class="btn-close"
                  data-bs-dismiss="modal"
                  aria-label="Close"
                ></button>
              </div>
              <form onsubmit="doSave();">
                <div class="modal-body">
                  <div class="row mb-3">
                    <label for="name" class="col-sm-2 col-form-label">Name</label>
                    <div class="col-sm-10">
                      <input type="text" class="form-control" id="name" required />
                      <input type="hidden" id="selectedId" value="" />
                    </div>
                  </div>
                  <div class="row mb-3">
                    <label for="name" class="col-sm-2 col-form-label">Gender</label>
                    <div class="col-sm-10">
                      <div class="form-check form-check-inline">
                        <input
                          class="form-check-input"
                          type="radio"
                          name="gender"
                          id="male"
                          value="male"
                          checked
                        />
                        <label class="form-check-label" for="male">남자</label>
                      </div>
                      <div class="form-check form-check-inline">
                        <input
                          class="form-check-input"
                          type="radio"
                          name="gender"
                          id="female"
                          value="female"
                        />
                        <label class="form-check-label" for="female">여자</label>
                      </div>
                    </div>
                  </div>
                  <div class="row mb-3">
                    <label for="company" class="col-sm-2 col-form-label"
                      >Company</label
                    >
                    <div class="col-sm-10">
                      <input
                        type="text"
                        class="form-control"
                        id="company"
                        required
                      />
                    </div>
                  </div>
                  <div class="row mb-3">
                    <label for="email" class="col-sm-2 col-form-label">Email</label>
                    <div class="col-sm-10">
                      <input
                        type="email"
                        class="form-control"
                        id="email"
                        required
                      />
                    </div>
                  </div>
                  <div class="row mb-3">
                    <label for="phone" class="col-sm-2 col-form-label">Phone</label>
                    <div class="col-sm-10">
                      <input
                        type="tel"
                        class="form-control"
                        id="phone"
                        pattern="^010-\d{3,4}-\d{4}$"
                        required
                      />
                    </div>
                  </div>
                  <div class="row mb-3">
                    <label for="phone" class="col-sm-2 col-form-label"
                      >Address</label
                    >
                    <div class="col-sm-10">
                      <div class="input-group mb-3">
                        <input
                          type="text"
                          class="form-control"
                          placeholder="주소"
                          id="address"
                          aria-label="주소"
                          aria-describedby="button-address"
                          requried
                        />
                        <button
                          class="btn btn-outline-secondary"
                          type="button"
                          id="button-address"
                          onclick="openDaumAPI();"
                        >
                          주소찾기
                        </button>
                      </div>
                    </div>
                  </div>
                </div>
                <div class="modal-footer">
                  <button
                    type="button"
                    class="btn btn-secondary"
                    data-bs-dismiss="modal"
                  >
                    닫기
                  </button>
                  <!-- submit은 <form> 태그 안에 있어야 한다. -->
                  <button type="submit" class="btn btn-primary">저장</button>
                </div>
              </form>
            </div>
          </div>
        </div>
        <!-- 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>
        <script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
        <script>
          async function doSearch() {
            const gender = document.querySelector("#gender").value;
            const name = document.querySelector("#searchName").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);
          }
    
          let customerData = [];
    
          function renderTable(data) {
            customerData = 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>`
              );
              h.push(
                `<td><a href="javascript:openModal('${item.id}');">${item.name}</a></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("");
          }
    
          function openModal(id) {
            console.log(id);
            selectedId = id;
            document.querySelector("#selectedId").value = id;
            let customer = customerData.filter((c) => c.id === id)[0];
            document.querySelector("#name").value = customer.name;
            document.querySelector("#company").value = customer.company;
            document.querySelector("#" + customer.gender).checked = true;
            document.querySelector("#email").value = customer.email;
            document.querySelector("#phone").value = customer.phone;
            document.querySelector("#address").value = customer.address;
    
            // 1.2 Modal - Passing options : 모달 창을 보여준다.
            var myModal = new bootstrap.Modal(
              document.querySelector("#customerModal")
            );
            myModal.show();
          }
    
          // 1.2 Modal - Passing options : 모달 창을 숨긴다.
          function closeModal() {
            selectedId = "";
            var myModal = new bootstrap.Modal(
              document.querySelector("#customerModal")
            );
            myModal.hide();
          }
    
          function formSubmit() {
            document.querySelector("#customerForm").submit();
            return false;
          }
    
          async function doSave() {
            event.preventDefault();
            const name = document.querySelector("#name").value.trim();
            const gender = document.querySelector("[name=gender]:checked").value;
            const company = document.querySelector("#company").value.trim();
            const email = document.querySelector("#email").value.trim();
            const phone = document.querySelector("#phone").value.trim();
            const address = document.querySelector("#address").value.trim();
    
            const selectedId = document.querySelector("#selectedId").value;
            Swal.fire({
              title: "정말 저장하시겠습니까?",
              //   text: "삭제된 데이터는 복원되지 않습니다!",
              icon: "warning",
              showCancelButton: true,
              confirmButtonColor: "#3085d6",
              cancelButtonColor: "#d33",
              confirmButtonText: "저장",
              cancelButtonText: "취소",
            }).then(async (result) => {
              if (result.isConfirmed) {
                const res = await fetch(
                  `http://localhost:3000/customers/${selectedId}`,
                  {
                    method: "PUT",
                    body: JSON.stringify({
                      name,
                      gender,
                      company,
                      email,
                      phone,
                      address,
                    }),
                    headers: {
                      "content-type": "application/json;charset=UTF-8",
                    },
                  }
                );
    
                if (res.status === 200) {
                  closeModal();
                  Swal.fire(
                    "저장 성공!",
                    "데이터가 정상적으로 저장 되었습니다.",
                    "success"
                  );
                } else {
                  Swal.fire("고객 정보를 저장하지 못했습니다. 다시 시도하세요.");
                }
              }
            });
          }
    
          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) {
            if (e.keyCode === 13) {
              doSearch();
            }
          }
        </script>
      </body>
    </html>

     

    [그림 1] 부트스트랩 모달 적용

     

    728x90
    반응형
    댓글