17장 ~ 19장
17장 웹 페이지에서 댓글 등록하기
이번 장에서는 댓글 등록을 위한 뷰 페이지를 만들고, JS 코드로 댓글 생성 요청을 보내고 응답 받는 것을 해보겠다.
그동안은 REST API 요청을 보낼 때 POSTMAN을 사용했었는데, 실제 게시판은 해당 웹 페이지에서 바로 요청을 보낸다.
이를 위해 사용하는 자바스크립트 API는 다음과 같다.
- document.querySelector() : 웹 페이지에서 특정 요소(버튼)를 찾아 반환
- addEventListener() : 특정 요소에 이벤트가 발생(버튼 클릭)했을 때 특정 동작(댓글 객체 전달) 수행
- fetch() : 웹 페이지에서 REST API 요청 (POST 요청)을 보낸다.
_new.mustache
<div class="card m-2" id="comments-new">
<div class="card-body">
<!-- 댓글 작성 폼 -->
<form>
<!-- 닉네임 입력 -->
<div class="mb-3">
<label class="form-label">닉네임</label>
<input type="text" class="form-control" id="new-comment-nickname">
</div>
<!-- 댓글 본문 입력 -->
<div class="mb-3">
<label class="form-label">댓글 내용</label>
<textarea type="text" class="form-control" rows="3" id="new-comment-body"></textarea>
</div>
<!-- 히든 인풋 -->
{{#article}}
<input type="hidden" id="new-comment-article-id" value="{{id}}">
{{/article}}
<!-- 전송 버튼 -->
<button type="submit" class="btn btn-primary" id="comment-create-btn">댓글 작성</button>
</form>
</div>
</div>
여기서 히든 인풋이란.
웹 페이지에 표시되지 않는 요소로, 보이지는 않지만 값을 가지고 있어야 할 때 사용한다.
이제 [댓글 작성] 버튼을 클릭했을 때 댓글을 입력할 수 있게 만들겠다.
이 부분은 자바스크립트로 구현한다...
자바스크립트로 댓글 달기
앞서 작성한 _new.mustache 밑에 <script> 태그를 추가한다.
querySelector는 웹페이지에서 특정 요소를 선택할 때 사용한다.
여기서는 특정 id 값을 이용하여 특정 요소를 찾았는데, id 값 앞에 #을 붙여서 찾았다.(이걸 아이디 선택자라고 한다.)
새 댓글 자바스크립트 객체 생성하기
<script>
{
// 댓글 생성 버튼 변수화
const commentCreateBtn = document.querySelector("#comment-create-btn");
// 댓글 클릭 이벤트 감지
commentCreateBtn.addEventListener("click", function(){
// 새 댓글 객체 생성
const comment = {
// 새 댓글의 닉네임
nickname: document.querySelector("#new-comment-nickname").value,
// 새 댓글의 본문
body: document.querySelector("#new-comment-body").value,
// 부모 게시글의 id
articleId: document.querySelector(" #new-comment-article-id").value
};
// 댓글 객체 출력
console.log(comment);
});
}
</script>
자바스크립트로 REST API 호출하고 응답 처리하기
이제는 fetch()함수를 이용하여 HTTP 통신을 해보겠다. ( GET, POST, PATCH, DELETE 같은 요청을 보내고 응답 받을 수 있다.)
// fetch() - 비동기 통신을 위한 API
const url = "/api/articles/" + comment.articleId + "/comments";
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(comment) //comment 객체를 JSON 문자열로 변환해 전송
}).then(response => {
// HTTP 응답 코드에 따른 메시지 출력
const msg = (response.ok) ? "댓글이 등록됐습니다." : "댓글 등록 실패..!";
alert(msg);
// 현재 페이지 새로 고침
window.location.reload();
});
[요청]
첫 번째 전달값 : API 주소
두 번재 전달값 : 요청 메서드, 헤더 정보, 전송 본문 (전송 본문은 comment 객체를 JSON 형태로 변환해 전송하기 위해 JSON.stringify() 메서드를 사용한다.)
1분 퀴즈 ) 다음 자바스크립트에 관한 설명 중 잘못된 것을 고르세요.
① alert()는 입력 문자열을 브라우저 콘솔에 출력한다.
② fetch()는 API 요청을 보내고 응답을 받아 처리할 수 있게 한다.
③ JSON.stringify()는 객체를 입력받아 JSON 문자열로 반환한다.
④ addEventListener()는 특정 요소가 이벤트를 감지해 처리하게 한다.
⑤ document.querySelector()는 웹 페이지에서 특정 요소를 찾아 반환한다.
답 : 1 -> 메시지가 뜨게 함..
18장 웹 페이지에서 댓글 수정하기
댓글 수정 페이지는 모달 창으로 구현할 것이다.
[ _list.mustache ]
<div id="comments-list">
{{#commentDtos}} <!--댓글 목록 순회-->
<div class="card m-2" id="comments-{{id}}">
<div class="card-header">
{{nickname}}
<button type="button"
class="btn btn-sm btn-outline-primary"
data-bs-toggle="modal"
data-bs-target="#comment-edit-modal"
data-bs-id="{{id}}"
data-bs-nickname="{{nickname}}"
data-bs-body="{{body}}"
data-bs-article-id="{{articleId}}">
수정</button>
</div>
<div class="card-body">
{{body}}
</div>
</div>
{{/commentDtos}}
</div>
<!-- Modal -->
<div class="modal fade" id="comment-edit-modal" tabindex="-1" >
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fs-5" id="exampleModalLabel">댓글 수정</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<!-- 댓글 수정 폼 -->
<form>
<!-- 닉네임 입력 -->
<div class="mb-3">
<label class="form-label">닉네임</label>
<input type="text" class="form-control" id="edit-comment-nickname">
</div>
<!-- 댓글 본문 입력 -->
<div class="mb-3">
<label class="form-label">댓글 내용</label>
<textarea type="text" class="form-control" rows="3" id="edit-comment-body"></textarea>
</div>
<!-- 히든 인풋 -->
<input type="hidden" id="edit-comment-id">
<input type="hidden" id="edit-comment-article-id">
<!-- 전송 버튼 -->
<button type="submit" class="btn btn-primary" id="comment-update-btn">수정 완료</button>
</form>
</div>
</div>
</div>
</div>
자바스크립트로 댓글 수정하기
[ _list.mustache ]
html 태그 밑에 <script> 태그 부분이다.
<!-- 모달 이벤트 처리 -->
<script>
{
// 모달 요소 선택
const commentEditModal = document.querySelector("#comment-edit-modal");
// 모달 이벤트 감지
commentEditModal.addEventListener("show.bs.modal", function (event) {
// 1. 트리거 버튼 선택
const triggerBtn = event.relatedTarget;
// 2. 데이터 가져오기
const id = triggerBtn.getAttribute("data-bs-id"); // id 가져오기
const nickname = triggerBtn.getAttribute("data-bs-nickname"); // 닉네임 가져오기
const body = triggerBtn.getAttribute("data-bs-body"); // 본문 가져오기
const articleId = triggerBtn.getAttribute("data-bs-article-id"); // 부모 id 가져오기
// 3. 수정 폼에 데이터 반영
document.querySelector("#edit-comment-nickname").value = nickname; // 닉네임 반영
document.querySelector("#edit-comment-body").value = body; // 댓글 본문 반영
document.querySelector("#edit-comment-id").value = id; // id 반영
document.querySelector("#edit-comment-article-id").value = articleId; // 부모 id 반영
});
}
</script>
기존의 댓글 데이터를 가져오고, 수정 버튼을 눌렀을 때 수정 폼에 이전 댓글 데이터가 전달될 수 있게 할 것이다.
[ 모달 동작 이벤트 타입 ]
show.bs.modal | 모달이 표시되기 직전 실행되는 이벤트 |
shown.bs.modal | 모달이 표시된 후 실행되는 이벤트 |
hide.bs.modal | 모달이 숨겨지기 직전 실행되는 이벤트 |
hidden.bs.modal | 모달이 숨겨진 후 실행되는 이벤트 |
위의 코드를 설명하자면,
show.bs.modal - 모달이 열리기 직전에 발생하는 이벤트를 의미하고,
function(event) 이벤트를 받아서 처리하는 함수로, 이벤트 핸들러라고 한다.
function(evnet) 의 event - 발생된 이벤트 정보를 가리키는 매개변수이며, 여기서는 show.bs.modal을 가리킨다.
히든 인풋 요소의 value 값 (댓글 id :5 , 부모 id : 5 )이 잘 들어있는 지 확인했다.]
수정 완료 버튼 클릭 시 REST API 호출 응답
{
// 수정 완료 버튼 선택
const commentUpdateBtn = document.querySelector("#comment-update-btn");
// 클릭 이벤트 처리
commentUpdateBtn.addEventListener("click", function() {
// 수정 댓글 객체 생성
const comment = { // 변수 선언
id: document.querySelector("#edit-comment-id").value,
nickname: document.querySelector("#edit-comment-nickname").value,
body: document.querySelector("#edit-comment-body").value,
article_id: document.querySelector("#edit-comment-article-id").value
};
console.log(comment); // 객체 생성 확인
// 수정 REST API 호출
const url = "/api/comments/" + comment.id;
fetch(url, {
method: "PATCH",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(comment) // comment 객체를 JSON 문자열로 변환 전송
}).then(response => {
// HTTP 응답 코드에 따른 메시지 출력
const msg = (response.ok) ? "댓글이 수정됐습니다." : "댓글 수정 실패...!";
alert(msg);
// 현재 페이지 새로 고침
window.location.reload();
});
});
}
1분 퀴즈) 다음 설명 중 옳은 것을 모두 고르세요.
① 모달은 웹 페이지 내부에서 상위 레이어를 띄우는 방식으로 사용하는 창이다.
② show.bs.modal 이벤트는 모달이 보여진 다음 수행된다.
③ HTML의 data-* 속성은 HTML 요소에 추가 정보를 저장하고 싶을 때 사용한다.
④ 이벤트 핸들러란 특정 이벤트를 처리하는 함수다.
⑤ JSON.stringify()는 문자열을 입력받아 자바스크립트 객체로 반환한다.
답: 1, 3, 5
19장 웹 페이지에서 댓글 삭제하기
댓글 삭제는
1. 댓글 [삭제] 버튼 추가
2. [삭제] 버튼 클릭 시 REST API 요청 보내기 방식 순으로 진행 예정이다.
먼저 뷰 페이지에 삭제 버튼을 추가했다.
[ _list.mustache ]
수정 버튼 태그 아래에 삭제 버튼 태그 추가
<!-- 댓글 삭제 버튼 -->
<button type="button" class="btn btn-sm btn-outline-danger comment-delete-btn"
data-comment-id="{{id}}">삭제</button>
댓글 삭제 스크립트
[ _list.mustache ]
<!-- 댓글 삭제 -->
<script>
{
// 삭제 버튼 선택
const commentDeleteBtn = document.querySelectorAll(".comment-delete-btn");
// 삭제 버튼 이벤트 처리
commentDeleteBtn.forEach(btn => {
btn.addEventListener("click", (event) => { // event 객체 받아오기
// 이벤트 발생 요소 선택
const commentDeleteBtn = event.target; // [삭제]버튼 변수화
// 삭제 댓글 id 가져오기
const commentId = commentDeleteBtn.getAttribute("data-comment-id"); // id 가져오기
console.log(`삭제 버튼이 클릭 : ${commentId}번 댓글`);
// 삭제 REST API 호출
const url = `/api/comments/${commentId}`;
fetch(url, {
method: "DELETE"
}).then(response => {
// 댓글 삭제 실패 처리
if (!response.ok) {
alert("댓글 삭제 실패...!");
return;
}
// 삭제 성공 시 댓글을 화면에서 지우고 메시지 창 띄우기
const target = document.querySelector(`#comments-${commentId}`);
target.remove();
const msg = `${commentId}번 댓글을 삭제했습니다.`;
alert(msg);
// 현재 페이지 새로 고침
window.location.reload();
});
});
});
}
</script>