본문 바로가기

Server Programming/Spring Boot Backend Programming

6장-3. 댓글의 자바스크립트 처리 (+Axios, @JsonFormat, @JsonIgnore)

반응형

동기식 : 여러 작업의 동시 처리가 불가능

비동기식 : 처리가 끝나면 '콜백'이라고 부르는 통보 방식으로, 하나의 작업이 끝날 때까지 기다리지 않고도 여러 작업의 동시 처리가 가능

 

자바의 람다식 : 자바에서 함수를 파라미터로 전달

-파라미터로 전달되는 콜백을 내부에서 호출하는 방식

 

자바스크립트의 함수 : 객체와 동일한 일급 객체로 파라미터가 되거나 리턴타입이 가능하다.

-함수를 이용해 콜백을 수행할 수 있다.

https://ko.javascript.info/callbacks

 

콜백

 

ko.javascript.info

-Promise : 비동기 호출을 동기화된 방식으로 작성하는 문법 기능

 

요구사항

  • 댓글 목록
  • 댓글 등록 / 조회 / 수정 / 삭제
  • 댓글 페이지 이동

댓글 처리가 필요한 화면을 작성하기 위한 Axios

-비동기 호출을 동기화된 방식으로 작성하는 문법 기능인 Promise를 활용해 구현한 라이브러리

-동기화된 방식으로 Ajax 호출 코드 작성

 

  • read.html : 이벤트 처리를 위한 자바스크립트만 존재하는 HTML 파일
  • reply.js : Axios를 이용한 비동기 통신를 위한 스크립트 파일

1. read.html에 Axios 라이브러리를 사용하기 위해 CDN / reply.js  추가

<div layout:fragment="content">
  <div class="row mt-3">
    <div class="col">
      <div class="card">
        <!--굵음-->
        <div class="card-header">
          Board Read-header
        </div>
        <!-- 카드 본문에 <form>태그로 게시물에 입력할 항목 추가-->
        <div class="card-body">
          <!-- 글번호-->
          <div class="input-group mb-3">
            <div class="input-group-text">Bno</div>
            <input type="text" class="form-control" th:value="${dto.Bno}" readonly>
          </div>
          <!--제목 -->
          <div class="input-group mb-3">
            <div class="input-group-text">Title</div>
            <input type="text" class="form-control" th:value="${dto.title}" readonly>
          </div>
          <!--내용 -->
          <div class="input-group mb-3">
            <div class="input-group-text">Content</div>
            <textarea class="form-control col-sm-5" rows="5" readonly>[[${dto.content}]]</textarea>
          </div>
          <!--작성자-->
          <div class="input-group mb-3">
            <div class="input-group-text">Writer</div>
            <input type="text" class="form-control" th:value="${dto.writer}" readonly>
          </div>
          <!--등록시간-->
          <div class="input-group mb-3">
            <div class="input-group-text">regDate</div>
            <input type="text" class="form-control" th:value="${#temporals.format(dto.regDate, 'yyyy-MM-dd HH:mm:ss')}" readonly>
          </div>
          <!--수정시간-->
          <div class="input-group mb-3">
            <div class="input-group-text">modDate</div>
            <input type="text" class="form-control" th:value="${#temporals.format(dto.modDate, 'yyyy-MM-dd HH:mm:ss')}" readonly>
          </div>
          <!--등록 / 초기화 버튼-->
           <div class="my-4">
                 <div class="float-end" th:with="link = ${pageRequestDTO.getLink()}">
                     <a th:href="|@{/board/list}?${link}|" class="text-decoration-none">
                         <button type="button" class="btn btn-primary">List</button>
                     </a>
                <a th:href="|@{/board/modify(bno=${dto.bno})}&${link}|" class="text-decoration-none">
                         <button type="button" class="btn btn-secondary">Modify</button>
                     </a>
                 </div>
             </div>


        </div>
      </div>
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script src="/js/reply.js"></script>

</div>

 

 

 

2. 댓글 추가 버튼 / 댓글 출력 / 댓글 페이징 처리 화면 구성

 

간격을 나타내는 mt, md, my

https://getbootstrap.kr/docs/5.0/utilities/spacing/

 

간격

Bootstrap에는 요소의 모양을 수정하기 위한 광범위한 반응형 gap, padding 및 margin 유틸리티 클래스가 포함되어 있습니다.

getbootstrap.kr

 

  </div> <!-- end 1row-->

  <!-- 2행 : 댓글 추가 버튼 -->
  <div class="row mt-3">
    <div class="col-md-12">
      <div class="my-4 ">
        <button class="btn btn-info addReplyBtn"> ADD REPLY</button>
      </div>
      <ul class="list-group replyList"></ul>
    </div> <!-- end col-->
  </div> <!-- end 2row-->
  <!-- 3행 : 댓글 목록 + 댓글 페이지 출력-->
  <div class="row mt-3">
    <div class="col">
      <ul class="pagination replyPaging">
      </ul>
    </div> <!-- end col-->
  </div> <!-- end 2row-->


  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script src="/js/reply.js"></script>

</div> <!--end content fragment -->

<ul> : 정렬되지 않은 리스트에 replyList, replyPaging 전달해 출력

 

3. Axios를 이용해 replyList, replyPaging 전달

https://yamoo9.github.io/axios/guide/usage.html

 

사용법 | Axios 러닝 가이드

사용법 GET 요청 axios를 사용해 GET 요청하는 방법은 다음과 같습니다. const axios = require('axios'); axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }) .t

yamoo9.github.io

 

-await, async : 비동기 처리를 동기화된 코드로 작성하기 위해 사용

-async : 비동기 처리를 위한 함수로, function 앞에 위치

-await : async 함수 내에서만 동작하는 키워드로, 프라미스가 처리될 때까지 기다렸다가 호출하는 메서드 [비동기 호출]

 

https://ko.javascript.info/async-await

 

async와 await

 

ko.javascript.info

 

(1) reply.js에 특정 게시물의 댓글 목록을 전달하는 get1() 메서드 작성

  • 메서드 명 : get1()
  • 파라미터 : bno

(2) read.html에서 reply.js의 get1() 함수 호출

  •  

(1) 콘솔창을 이용해 데이터 확인

async function get1(bno){
    const result = await axios.get(`/replies/list/${bno}`)

    //(1) 데이터를 콘솔창을 이용해 미리 확인
    console.log(result)

}

 

<script>
  //reply.js에서 get1()호출 결과를 반환해 replyList에 저장
  const bno=[[${dto.bno}]]
  //(1) 데이터를 콘솔창을 이용해 미리 확인
  get1(bno)
  
</script>

 

(2) 화면에서 결과를 나타내기 위해 비동기 함수 get1()의 리턴 값 반환

async function get1(bno){
    const result = await axios.get(`/replies/list/${bno}`)

    //(1) 데이터를 콘솔창을 이용해 미리 확인
    // console.log(result)

    //(2) 화면에서 결과를 확인하기 위한 리턴값
    return result.data
}

 

<script>
  //reply.js에서 get1()호출 결과를 반환해 replyList에 저장
  const bno=[[${dto.bno}]]
  //(1) 데이터를 콘솔창을 이용해 미리 확인
  // get1(bno)
  //(2) 화면에서 결과를 확인하기 위해
  console.log(get1(bno))
</script>

->하지만 Promise가 반환되고, 반면에 실행 결과는 log 이후에 실행?

 

  1. 비동기 함수인 get1() 호출 시점에 반환값이 존재하지 않는다.
  2. 반환할 것이라는 '약속'만 반환한다.
  3. 비동기 처리 결과를 반환해서 처리하기 위해서는 then()catch()를 이용해 함수를 작성 한다

 

참고

  • async/await와 promise.then/catch

문법 제약 때문에 async함수 바깥의 최상위 레벨 코드에선 await를 사용할 수 없습니다.

그렇기 때문에 관행처럼 .then/catch를 추가해 최종 결과나 처리되지 못한 에러를 다룹니다. 

// 유효한 사용자를 찾을 때까지 반복해서 username을 물어봄
async function demoGithubUser() {

  let user;
  while(true) {
    let name = prompt("GitHub username을 입력하세요.", "iliakan");

    try {
      user = await loadJson(`https://api.github.com/users/${name}`);
      break; // 에러가 없으므로 반복문을 빠져나옵니다.
    } catch(err) {
      if (err instanceof HttpError && err.response.status == 404) {
        // 얼럿 창이 뜬 이후에 반복문은 계속 돕니다.
        alert("일치하는 사용자가 없습니다. 다시 입력해 주세요.");
      } else {
        // 알 수 없는 에러는 다시 던져집니다.
        throw err;
      }
    }
  }


  alert(`이름: ${user.name}.`);
  return user;
}

https://ko.javascript.info/promise-error-handling

 

프라미스와 에러 핸들링

 

ko.javascript.info

 

 

<script>
  //reply.js에서 get1()호출 결과를 반환해 replyList에 저장
  const bno=[[${dto.bno}]]
  //(1) 데이터를 콘솔창을 이용해 미리 확인
  // get1(bno)
  //(2) 화면에서 결과를 확인하기 위해
  console.log(get1(bno))
  //(3) then/catch 이용
  get1(bno).then(data =>{
    console.log(data)
  }).catch(e=>{
    console.error(e)
  })


</script>

 

(3) 비동기 처리 방식의 결정

 

  • 비동기 함수의 분리
    • 비동기 함수 : 비동기 통신만 처리
    • 호출한 함수 : then(), catch()로 이용해 처리
  • 비동기 함수에서 모두 처리
    • 비동기 함수에서 나중에 처리할 내용을 별도의 함수로 빼서 파라미터로 전달

: 비동기 함수를 분리하는 방식을 선택해, Promise 반환시 호출한 함수에서 then()처리하는 방식으로 구현한다.

 


메서드 명 getList addReply getReply modifyReply removeReply
파라미터 {bno, page,
size,goLast}
replyObj replyObj rno rno
호출 URL get(`/replies/list/${bno}`) post(`/replies/`) get(`/replies/
${rno}`)
put(`/replies/
${replyObj.rno}`)
delete(`/replies/
${rno}`)
URL 호출 파라미터 {params:
 {page, size}
replyObj X replyObj X
호출하는 함수 printReplies addEventListener addEventListener addEventListener addEventListener

1. 댓글 목록을 화면에 출력

  • 비동기 처리 함수 : reply.js의 getList()
    • 메서드 명 : getList()
    • 파라미터 : bno, page, size, goLast
    • 리턴 값 : result.data
    • get방식으로 파라미터로 page, size로 페이지 관련정보를 전달해 게시물의 댓글 목록을 가져와 result에 저장
  • 호출하는 함수 : read.html의 printReplies()
    • 메서드 명 : printReplies()
    • 파라미터 : page, size, goLast
    • 결과 : data => console.log(data)로 출력
    • 특징 : then(), catch()를 이용해 에러 핸들링
  • 비동기 처리 방식 :
    1. read.html에서 비동기 처리를 위해 reply.js의 비동기 함수를 호출한다.
    2. Promise 반환시 호출한 함수에서 then()처리를 수행한다.
  • 비동기 함수를 호출하는 printReplies()에서 호출하는 함수
    • replyList, replyPaging를 요소로 검색해 DOM 변수 설정
    • printLIst()함수와 printPages()함수에서 해당 DOM에 해당하는 문자열 추가

https://ko.javascript.info/searching-elements-dom

 

getElement*, querySelector*로 요소 검색하기

 

ko.javascript.info

(1) reply.js에 비동기 처리 함수 getList() 작성

-파라미터 여러개 : ({~, ~, ~, ~})

async function getList({bno, page, size, goLast}){
    const result = await axios.get(`/replies/list/${bno}`, {params: {page,size}})

    // 화면에서 결과를 확인하기 위한 리턴값
    return result.data
}

 

(2) read.html에 비동기 처리 함수 호출하는 함수 printReplies() 작성

  //reply.js에서 getList()호출 결과를 반환해 댓글 목록 출력, 페이지 목록 출력
  const bno=[[${dto.bno}]]

  //댓글 목록 비동기 처리 함수 호출
  function printReplies(page,size, goLast){
    getList({bno, page,size, goLast}).then(
            //로그에 댓글 목록 출력
            data=> {console.log(data)}
    ).catch(e=>{
      console.error(e)
    })
  }

  //무조건 호출
  printReplies(1,10)

</script>

(2) replyList, replyPaging를 요소로 검색해 DOM 변수 설정

//DOM 설정
const replyList = document.querySelector('.replyList');
const replyPaging = document.querySelector('.replyPaging');

 

(3) 댓글 목록 출력 함수 작성

//댓글 목록 DOM 생성 함수
function printList(dtoList) {
  let str='';

  if(dtoList && dtoList.length>0){
    for(const dto of dtoList){
      //문자열로 생성
          str+=`<li class="list-group-item d-flex replyItem">
                  <span class="col-2"> ${dto.rno}</span>
                  <span class="col-6" data-rno="${dto.rno}"> ${dto.replyText}</span>
                  <span class="col-2"> ${dto.replyer}</span>
                  <span class="col-2"> ${dto.regDate}</span>
                </li>`
    }
  }
  replyList.innerHTML=str
}

(4) 페이지 목록 출력 함수 작성

//댓글 페이지 목록 DOM 생성 함수
function printPages(data) {
  //pagination
  let pageStr = '';
  
  //이전 페이지 존재할 경우
  if (data.prev){
    pageStr+=`<li class="page-item"><a class="page-link" 
                      data-page="${data.start-1}">PREV</a></li>`
  }
  //현재 페이지부터 마지막 페이지까지
  //: 현재 페이지는 active 처리
  for(let i=data.start; i<=data.end; i++){
    pageStr+=`<li class="page-item ${i==data.page?"active":""}">
                  <a class="page-link" data-page="${i}">${i}</a></li>`
  }
  //다음 페이지 존재할 경우
  if(data.next){
    pageStr+=`<li class="page-item"><a class="page-link" 
                      data-page="${data.end+1}">NEXT</a></li>`
  }
  replyPaging.innerHTML=pageStr
}

(5) 비동기 함수 호출하는 printReplies()에서 댓글 목록 출력함수와 페이지 목록 출력 함수 호출

//댓글 목록을 반환하는 비동기 처리 함수 호출
function printReplies(page,size, goLast){
  getList({bno, page,size, goLast}).then(
          //로그에 댓글 목록 출력
          //data=> {console.log(data)}
          data=> {
            printList(data.dtoList)
            printPages(data)
          }
  ).catch(e=>{
    console.error(e)
  })
}

//무조건 호출
printReplies(1,10,true)

 

 

(6) JSON 문자열 데이터 조작

JSON 포맷팅과 JSON 변환 시 제외

-@JsonFormat : JSOn 처리시에 포맷팅을 지정하는 어노테이션

-@JsonIgnore : JSON 변환시에 제외하는 어노테이션

 

-ReplyDTO에서 JSON 문자열 데이터 조작을 위해 어노테이션 지정

 

변경 전, ReplyDTO

package org.zerock.b01.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ReplyDTO {

    private Long rno;
    //특정 게시글의 번호를 지정하기 위한 멤버변수
    @NotNull
    private Long bno;

    @NotEmpty
    private String replyText;

    @NotEmpty
    private String replyer;

    private LocalDateTime regDate, modDate;
}

 

변경 후, ReplyDTO

package org.zerock.b01.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ReplyDTO {

    private Long rno;
    //특정 게시글의 번호를 지정하기 위한 멤버변수
    @NotNull
    private Long bno;

    @NotEmpty
    private String replyText;

    @NotEmpty
    private String replyer;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime regDate;
    
    @JsonIgnore
    private LocalDateTime modDate;
}

 

(7) 댓글 등록시 마지막 페이지로 이동하기 위한 getList() 메서드 변경

-댓글이 추가되는 경우 마지막 페이지에 등록된다.

-확인을 쉽게 하기 위해 댓글 목록 데이터의 total을 이용해 마지막 페이지 호출한다.

-서버를 다시 호출하는 방식으로 호출하는 경우의 수를 최대한 줄여서 부하를 줄이는 방식을 사용하곤 한다.

 

-페이징 처리를 하기 때문에 최신 댓글을 볼 수 없기 때문에,

현재 게시물 댓글의 마지막 페이지를 이용해 마지막 페이지를 다시 호출한다.

-> 마지막 페이지 호출 : total값과 size값으로 마지막 페이지 계산해 Axios로 호출

  • goLast가 true인 경우
    • total : 총 페이지 수
    • lastPage : 마지막 페이지 수
      (총 페이지 수 / 페이지 단위)의 올림수 -> 1개의 댓글이라도 있으면 1페이지가 할당되기 때문에
    • 리턴 값 : 마지막 페이지의 댓글을 출력하기 위해 댓글 목록을 리턴하는 getList() 함수에 마지막 페이지를 파라미터로 전달
//댓글 마지막 페이지로 이동
async function getList({bno, page, size, goLast}){
    const raw = await axios.get(`/replies/list/${bno}`)

    console.log(raw)
    const result = await axios.get(`/replies/list/${bno}`, {params: {page, size}})


    if(goLast){
        const total = result.data.total
        const lastPage = parseInt(Math.ceil(total/size))

        return getList({bno:bno, page:lastPage, size:size})

    }

 

//댓글 마지막 페이지로 이동
printReplies(1,10, true)

 

 


2. 댓글 등록

모달창을 이용해 처리

  • 새로운 댓글의 replyText, replyer 입력
  • 자바스크립트 객체로 POST 호출

동작 순서

  1. reply.js에서 addReply() 메서드 호출
  2. addReply() 메서드에서 JSON 데이터를 전송
  3. JSON 데이터를 이용해 댓글을 등록
  4. 댓글 등록 완료시  등록된 댓글이 있는 마지막 페이지로 이동

 

(1) reply.js에 댓글 등록 메서드 작성

-자바스크립트 객체로 파라미터를 받아서 axios.post() 이용해서 전달

https://yamoo9.github.io/axios/guide/usage.html#post-%EC%9A%94%EC%B2%AD

 

사용법 | Axios 러닝 가이드

사용법 GET 요청 axios를 사용해 GET 요청하는 방법은 다음과 같습니다. const axios = require('axios'); axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }) .t

yamoo9.github.io

 

axios.post() 기본 문법

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

 

(2) reply.js의 addReply() 작성

//댓글 등록 메서드
async function addReply(replyObj){
    const response = await axios.post(`/replies/`, replyObj)
    
    return response.data
}

-> 키와 값으로 이루어진 JSON 데이터를 전송한다.

-> '{'rno':11}'와 같은 형태의 JSON 데이터

 

(3) read.html에 모달창 추가

 

https://getbootstrap.kr/docs/5.2/components/modal/

 

모달

Bootstrap JavaScript 모달 플러그인을 사용하여 라이트박스, 사용자 알림 또는 사용자 정의 콘텐츠를 만들 수 있습니다.

getbootstrap.kr

모달창 기본 구조

<div class="modal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p>Modal body text goes here.</p>
      </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">Save changes</button>
      </div>
    </div>
  </div>
</div>

 

<fragment="content"> 마지막에 댓글 등록을 위한 모달창 추가

  <!-- 댓글 등록을 위한 모달창-->
  <div class="modal registerModal" tabindex="-1">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title">Register Reply</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <div class="input-group mb-3">
          <span class="input-group-text">Reply Text</span>
<!--          <p>Modal body text goes here.</p>-->
          <input type="text" class="form-control replyText">
        </div>
          <div class="input-group mb-3">
          <span class="input-group-text">Replyer</span>
<!--          <p>Modal body text goes here.</p>-->
          <input type="text" class="form-control replyer">
        </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-primary registerBtn">Register</button>
          <button type="button" class="btn btn-online-dark closeRegisterBtn">Close</button>
        </div>
      </div>
    </div>
  </div>

-> class 속성값을 이용해 <input> 태그와 버튼들을 구분

 

(2) read.html의 <script>부분에 사용할 DOM 객체들을 미리 변수로 처리

//변수 설정
//댓글 등록 모달창
const registerModal =new bootstrap.Modal(document.querySelector(".registerModal"))
//input 태그
const replyText = document.querySelector(".replyText")
const replyer  = document.querySelector(".replyer")
// 버튼
const registerBtn = document.querySelector(".registerBtn")
const closeRegisterBtn = document.querySelector(".closeRegisterBtn")

 

(3) 모달창 열고 닫는 이벤트 처리

  //모달창 열고 닫는 이벤트 처리
  document.querySelector(".addReplyBtn").addEventListener("click", function (e){
    registerModal.show()
  },false)
  document.querySelector(".closeRegisterBtn").addEventListener("click", function (e){
    registerModal.hide()
  },false)

(4) 댓글 등록하는 모달창 이벤트 처리

//댓글 등록하는 모달창 이벤트 처리 
document.querySelector(".registerBtn").addEventListener("click", function (e){
  const replyObj = {
    bno:bno,
    <!-- String은 value로 값을 가져온다-->
    replyText:replyText.value,
    replyer : replyer.value
  }
  <!-- addReply에 파라미터 전달-->
  addReply(replyObj).then(result => {
    alert(result.rno)
    registerModal.hide()
    // 등록 후에는 변수 초기화 
    replyText.value=''
    replyer.value=''
    //댓글 목록 갱신해서 마지막 페이지로 이동
    printReplies(1,10,true)
  }).catch(e =>{
    alert("Exception...")
  })
  },false)

3. 댓글 조회

-특정 댓글 조회시, 수정 및 삭제를 할 수 있는 모달창 띄우기

(1) reply.js에 댓글 조회를 위한 메서드 작성

//댓글 조회를 위한 메서드
async function getReply(rno){
    const response = await axios.get(`/replies/${rno}`)
    return response.data
}

(2) read.html 모달창 추가

-새로운 모달창을 추가해 사용

4. 댓글 수정

(1) reply.js에 댓글 수정을 위한 메서드 작성

//댓글 수정을 위한 메서드
async function modifyReply(replyObj){
    const response = await axios.put(`/replies/${replyObj.rno}`)
    return response.data
}

(2) read.html 조회시 추가한 모달창을 이용해 수정 처리

-댓글 수정 후에 다시 현재 페이지 호출하도록 수정된 댓글을 확인할 수 있도록 한다.
(하지만 수정 과정에서 많은 댓글이 달릴 경우 확인하지 못할 수도 있다.)

 

5. 댓글 삭제

(1) reply.js에 댓글 삭제를 위한 메서드 작성

//댓글 수정을 위한 메서드
async function modifyReply(replyObj){
    const response = await axios.put(`/replies/${replyObj.rno}`,replyObj)
    return response.data
}

(2) read.html 조회시 추가한 모달창을 이용해 삭제 처리

 

6. 댓글 조회/수정/삭제 이벤트 처리

(1) 사용할 변수 초기화

//댓글 조회/수정/삭제 모달창 띄우기
//댓글 조회/수정/삭제 클래스 모달창/속성값 변수 설정
const modifyModal = new bootstrap.Modal(document.querySelector(".modifyModal"))
const replyHeader = document.querySelector(".replyHeader")
const modifyText = document.querySelector(".modifyText")
const modifyBtn = document.querySelector(".modifyBtn")
const removeBtn = document.querySelector(".removeBtn")
const closeModifyBtn = document.querySelector(".closeModifyBtn")

(2) 댓글 클릭시 모달창 띄우기

-댓글 내용을 채워서 띄운다.

//댓글 클릭시 모달창 띄우기
replyList.addEventListener("click", function (e){
  e.preventDefault()
  e.stopPropagation()

  const target=e.target
  if(!target || target.tagName!='SPAN'){
    return
  }
  const rno = target.getAttribute("data-rno")

  if(!rno){
    return
  }

  getReply(rno).then(reply =>{
    //댓글 내용을 모달창에 띄우기
    console.log(reply)
    //댓글을 구별하기 위한 변수
    replyHeader.innerHTML=reply.rno
    //String값은 value로 접근
    modifyText.value=reply.replyText
    //댓글 내용을 채운 모달창 띄우기
    modifyModal.show()
  }).catch(e=>alert('error'))
},false)

 

 

(3) 댓글 수정/닫기/삭제 버튼 이벤트 처리

-댓글 수정 후 처리하는 경우 수정하는 사이 댓글 추가시 확인할 수 없다.

-현재 페이지를 유지하도록 구현한다.

-Modify 버튼 클릭시 수정 처리, Close 버튼 클릭시 모달창 끄기 처리

//수정 버튼 이벤트 처리
modifyBtn.addEventListener("click",function (e){
  //입력받은 내용을 필요한 파라미터를 채워서 객체로 전달
  //: rno를 replyHeader의 주소로 지정한다.
  const replyObj={
    bno:bno,
    rno:replyHeader.innerHTML,
    replyText:modifyText.value
  }
  //수정한 댓글 출력하고, 댓글을 수정하던 페이지 정보를 이용해 이전 페이지로 이동
  modifyReply(replyObj).then(result =>{
    alert(result.rno+' 번 댓글이 수정되었습니다.')
    replyText.value=''
    modifyModal.hide()
    printReplies(page,size)
  }).catch(e=> {
    console.log(e)
  })

},false)

//닫기 버튼 클릭시 모달창 이벤트 처리
closeModifyBtn.addEventListener("click", function (e){
  modifyModal.hide()
},false)

  //삭제 버튼 클릭시 모달창 이벤트 처리
  removeBtn.addEventListener("click", function (e){
    //rno
    removeReply(replyHeader.innerHTML).then(result=>{
      alert(result.rno+' 번 댓글이 삭제되었습니다.')
      //댓글 삭제 후, 변수 초기화
      replyText.value=''
      modifyModal.hide()
      
      //1페이지로 이동하기 위한 변수
      page=1
      
      //댓글 목록 출력 
      printReplies(page, size)
    })
  },false)

 

7. 댓글 페이지 이동 이벤트 처리

-'data-page' 속성을 이용해 페이지 번호가 지정되어 있다.

-이벤트 처리를 위해 고정된 <ul>을 대상으로 이벤트 리스너 등록

https://ko.javascript.info/dom-attributes-and-properties

 

속성과 프로퍼티

 

ko.javascript.info

https://dololak.tistory.com/364

 

[자바스크립트] 데이터 속성(data-xxx)에 대해

데이터 속성 HTML5부터는 데이터 속성이라는 개념이 생겼습니다. 데이터 속성은 HTML 요소의 'data-' 로 시작하는 속성입니다. 이러한 데이터 속성은 특정한 데이터를 DOM 요소에 저장해두기 위함이

dololak.tistory.com

 

 

//댓글 페이지 번호 이벤트 처리
//(1) 사용할 변수 초기화
let page=1
let size=10
//(2) 고정된 ul에 이벤트 리스너 등록
document.querySelector(".replyPaging").addEventListener("click", function (e){
  e.preventDefault()
  e.stopPropagation()

  const target = e.target

  if(!target || target.tagName!='A'){
    return
  }

  //(3) data-page 속성에 저장된 페이지 번호를 변수로 설정
  const pageNum = target.getAttribute("data-page")

  //(4) 페이지 번호를 파라미터에 저장하고, 댓글 목록을 출력하는 printReplies 함수를 해당 파라미터를 전달해 호출
  page=pageNum
  printReplies(page,size)
},false)

 

반응형