https://velog.io/@wonizizi99/TIL-23.02.17
2.17 댓글 보여주기 구현을 했으나 자세히 보니 부모댓글도 한칸씩 밀려 들어가는 것을 볼수 있었다.
결과: ....부모댓글은 나오지만 대댓글 구현이 쉽지 않다. ㅠㅠ 값을 불러오는데서 for문 안에서만 문제가 생기는 건 뭔지..
결과: 자바스크립트에서 depth를 만들어 들여쓰기 구현등, 재귀함수 사용하여 1차 구현 >.<ㅎ
원인 : 2차시도의 문제점은 부모댓글도 함께 들여쓰기가 되어 자식댓글처럼 보였다.
결과 : 부모댓글은 첫줄에 있고 , 자식댓글만 한칸씩 들여쓰기를 하여 계층구조 구현
해결 방법 : 서버쪽에서 댓글의 depth를 구현하여 깊이만큼 들여쓰기를 하여 계층구조를 표현 할 수 있었다.
서비스 로직이 comment 댓글 엔티티 하나로 대댓글 구현하여
재귀함수로 댓글을 보여주는 형식이 적용 되었다.
재귀로 사용할 수 있었던것 대댓글이 몇백개 달리지는 않을것을 예상하여 적용할 수 있었다.
알게 된점 : 벡엔드만 할때는 뎁스없이도 계층구조로 볼수 있었지만 , 프론트를 위한 값도 벡엔드에서 구현해야 한다는 것을 알수 있었다.
댓글 보여주기 부분 코드
//------------------------ 댓글 보여주기 ------------------------
function showComment(commentList, depth) {
if (commentList.length === 0) {
return; //탈출조건
}
for (let index = 0; index < commentList.length; index++) {
const singleComment = commentList[index];
const depth = singleComment['depth']
let temp_html = makeCommentHtml(singleComment,depth)
$('#commentShow').append(temp_html)
showComment(singleComment['children'], depth);
}
}
function makeCommentHtml(singleComment,depth) {
var space = ""
var point = ""
if(depth>=2){
point ="ㄴ "
}
for (let i = 1; i < depth; i++) {
space = space + "      "
}
var nickName = singleComment['nickName']
return `<div class="d-flex">
<div class="ms-3">
<div class="fw-bold">${space}${point}작성자:${singleComment['nickName']}</div>
<div class="text-black-50">${space}${singleComment['comments']}</div>
<p class="text-black-50">${space}${singleComment['createdDate']}
<button name="creatRe" id="reply_${singleComment['id']}" >답글</button>
<button name="editComment" id ="edit_${singleComment['id']}">수정</button>
<button name="delComment" id ="comment_${singleComment['id']}">삭제</button>
<span style="display: none ;" id="toggleEdit_${singleComment['id']}">
<textarea id="editCommentContent_${singleComment['id']}"></textarea>
<button name="saveEdit" id="commentEdit_${singleComment['id']}">댓글수정</button>
</span>
<span style="display: none ;" id="toggleRe_${singleComment['id']}">
<textarea id="replyCommentContent_${singleComment['id']}"></textarea>
<button name="saveRe" id="commentSave_${singleComment['id']}">답글작성</button>
</span>
<div class="d-flex mt-4">
<div class="ms-3" id='commentReply_${singleComment['id']}'>
</div>
</p>
</div>
</div>`
}
전체코드
<script>
//-------- 로드실행----------------------------------------
$(document).ready(function () {
var param = document
.location
.href
.split("?");
console.log(param[1])
var settings = {
"url": "http://localhost:8080/api/contact/inquiries/" + param[1],
"method": "GET",
"timeout": 0
};
//----------------------------------agax --------------------------- 필요변수 여기에 선언
$
.ajax(settings)
.done(function (response) {
console.log(response);
let inquiryId = response['id']
let title = response['title']
let content = response['content']
let createdDate = response['createdDate']
let username = response['username']
let nickName = response['nickName']
//------------------------------ 게시글 보여주기 -----------------------------------
let temp_html = `<div class="container" id= inquiryBox>
<table class="table table-hover" width="1000" id="textBox">
<tr>
<td>제목 </td>
<td colspan="4" align="left">${title}</td>
</tr>
<tr align="center">
<td>작성일</td>
<td>${createdDate}</td>
<td>작성자</td>
<td>${nickName}</td>
</tr>
<tr height="300">
<td colspan="5" align="left">${content}</td>
</tr>
</table>
<button type="button" class="btn btn-outline-secondary border">
<a href="contactPageIndex-inquiry.html">목록보기</a>
</button>
<button type="button" class="btn btn-outline-secondary border" id="b-edit">
<a href="contactEdit-inquiry.html?${inquiryId}">수정</a>
</button>
<button type="button" class="btn btn-outline-secondary border" name ='b-delete'>
<a href="contactPageIndex-inquiry.html">삭제</a>
</button>
<section class="mb-5">
<div class="card bg-light">
<div class="card-body" id = "commentShow">
<!-- Comment form-->
<form class="mb-4"><textarea id ="t-commentSave"class="form-control" rows="3" placeholder="댓글을 남겨주세요"></textarea>
<button type="button" name='b-commentSave'>댓글등록</button></form>
</div>
</div>
</section>
</div>`
$('#t-inquiry').append(temp_html)
showComment(response['comments'], 0)
//------------------------ 댓글 보여주기 ------------------------
function showComment(commentList, depth) {
if (commentList.length === 0) {
return; //탈출조건
}
for (let index = 0; index < commentList.length; index++) {
const singleComment = commentList[index];
const depth = singleComment['depth']
let temp_html = makeCommentHtml(singleComment,depth)
$('#commentShow').append(temp_html)
showComment(singleComment['children'], depth);
}
}
function makeCommentHtml(singleComment,depth) {
var space = ""
var point = ""
if(depth>=2){
point ="ㄴ "
}
for (let i = 1; i < depth; i++) {
space = space + "      "
}
var nickName = singleComment['nickName']
return `<div class="d-flex">
<div class="ms-3">
<div class="fw-bold">${space}${point}작성자:${singleComment['nickName']}</div>
<div class="text-black-50">${space}${singleComment['comments']}</div>
<p class="text-black-50">${space}${singleComment['createdDate']}
<button name="creatRe" id="reply_${singleComment['id']}" >답글</button>
<button name="editComment" id ="edit_${singleComment['id']}">수정</button>
<button name="delComment" id ="comment_${singleComment['id']}">삭제</button>
<span style="display: none ;" id="toggleEdit_${singleComment['id']}">
<textarea id="editCommentContent_${singleComment['id']}"></textarea>
<button name="saveEdit" id="commentEdit_${singleComment['id']}">댓글수정</button>
</span>
<span style="display: none ;" id="toggleRe_${singleComment['id']}">
<textarea id="replyCommentContent_${singleComment['id']}"></textarea>
<button name="saveRe" id="commentSave_${singleComment['id']}">답글작성</button>
</span>
<div class="d-flex mt-4">
<div class="ms-3" id='commentReply_${singleComment['id']}'>
</div>
</p>
</div>
</div>`
}
// ----------------------------------댓글보여주기 끝--------------------------------------------
});
// ----------------------------------ajax get 끝--------------------------------------------
});
// ----------------------------------로드시 실행되는부분 끝-------------------------------------------
// ----------------[해당버튼 클릭시 댓글쓰기]---------------
$('#t-inquiry').on("click", "button[name='b-commentSave']", function () {
var param = document.location.href.split("?");
var settings = {
"url": "http://localhost:8080/api/comments/inquiry/" + param[1],
"method": "POST",
"timeout": 0,
"headers": {
"Authorization": localStorage.getItem('accessToken'),
"Content-Type": "application/json"
},
"data": JSON.stringify({
"comments": $('#t-commentSave').val(),
}),
};
$.ajax(settings).done(function (response) {
console.log(response);
alert(response)
window.location.reload()
});
})
// -----[해당 버튼 클릭시 댓글삭제]-----------
$('#t-inquiry').on("click", "button[name='delComment']", function(){
var id_by_name = $(this).attr('id')
console.log(id_by_name)
var commentId = id_by_name.split("_")[1]
console.log(commentId)
var settings = {
"url": "http://localhost:8080/api/comments/"+commentId+"/inquiry",
"method": "DELETE",
"timeout": 0,
"headers": {
"Authorization": localStorage.getItem('accessToken')
},
};
$.ajax(settings).done(function (response) {
console.log(response);
alert(response)
window.location.reload();
}).fail(function(response){
console.log(response.responseJSON);
if(response.responseJSON.statusCode === 403){
alert(response.responseJSON.message)
}
});
})
// -----[해당 버튼 클릭시 답글 수정 창 나옴]-------------------
$('#t-inquiry').on("click", "button[name='editComment']", function(){
var id_by_name = $(this).attr('id')
var commentId =id_by_name.split("_")[1]
$("#toggleEdit_"+commentId).toggle();
})
// ---------------------------------------------------------
// -----[해당 버튼 클릭시 댓글수정 요청]----------------------
$('#t-inquiry').on("click", "button[name='saveEdit']", function(){
var id_by_name = $(this).attr('id')
var commentId = id_by_name.split("_")[1]
var settings = {
"url": "http://localhost:8080/api/comments/"+commentId+"/inquiry",
"method": "PUT",
"timeout": 0,
"headers": {
"Authorization": localStorage.getItem('accessToken'),
"Content-Type": "application/json"
},
"data": JSON.stringify({
"comments": $('#editCommentContent_'+commentId).val()
}),
};
$.ajax(settings).done(function (response) {
console.log(response);
alert(response)
window.location.reload();
}).fail(function(response){
console.log(response.responseJSON);
if(response.responseJSON.statusCode === 403){
alert(response.responseJSON.message)
window.location.reload();
}
if(response.responseJSON.statusCode === 404){
alert("다른 유저의 댓글은 수정할 수 없습니다.")
window.location.reload();
}
});
})
// -----[해당 버튼 클릭시 답글적는창 나옴]-------------------
$('#t-inquiry').on("click", "button[name='creatRe']", function(){
var id_by_name = $(this).attr('id')
console.log(id_by_name)
var commentId =id_by_name.split("_")[1]
console.log("★"+commentId)
$("#toggleRe_"+commentId).toggle();
})
// ---------------------------------------------------------
// -----[해당 버튼 클릭시 답글DB로 보냄]-------------------todo : 답글보여지는 위치에서 에러남
$('#t-inquiry').on("click", "button[name='saveRe']", function(){
var param = document.location.href.split("?");
console.log(param[1])
var id_by_name = $(this).attr('id')
console.log(id_by_name)
var commentId = id_by_name.split("_")[1]
console.log("☆"+commentId)
var settings = {
"url": "http://localhost:8080/api/comments/inquiry/"+param[1],
"method": "POST",
"timeout": 0,
"headers": {
"Authorization": localStorage.getItem('accessToken'),
"Content-Type": "application/json"
},
"data": JSON.stringify({
"comments": $('#replyCommentContent_'+commentId).val(),
"parentId": commentId
}),
};
$.ajax(settings).done(function (response) {
console.log(response);
alert(response)
window.location.reload();
}).fail(function(response){
console.log(response.responseJSON);
if(response.responseJSON.statusCode === 403){
alert(response.responseJSON.message)
}
});
})
commentService 댓글 저장로직
에서 뎁스와 parentId가 정해진다.
그럼으로 부모댓글과 자식댓글로 나뉘어 지고, 부모댓글은 자식댓글들을 가지게 된다.
commentService
@Override
public void saveInquiryComment(Long inquiryId,
CreateContactCommentRequest createContactCommentRequest,
String username) {
String nickName = userService.nickNameFindByUsername(username);
if (!inquiryRepository.existsById(inquiryId)) {
throw new CustomException(ExceptionStatus.BOARD_NOT_EXIST);
} else {
/**부모댓글이 있는 경우 - 대댓글 등록. 즉 자식 댓글이 됨 */
ContactComment parent = null;
if (createContactCommentRequest.getParentId() != null) {
parent = contactCommentRepository.findById(createContactCommentRequest.getParentId())
.orElseThrow(
() -> new CustomException(ExceptionStatus.COMMENT_NOT_EXIST)
);
/** 부모 댓글과 자식 댓글의 게시글 아이디가 같은지 확인*/
if (!parent.getInquiryId().equals(inquiryId)) {
throw new CustomException(ExceptionStatus.WRONG_POST_ID);
}
int depth = parent.getDepth();
ContactComment contactComment = createContactCommentRequest.toEntity(inquiryId, username,
nickName, parent,depth);
// ContactComment contactComment = new ContactComment(comments,inquiryId,username,parent);
depth = contactComment.getDepth()+1;
contactComment.getParent().setId(createContactCommentRequest.getParentId());
contactComment.setDepth(depth);
contactCommentRepository.save(contactComment);
/**부모댓글이 없는 경우 - 댓글 등록*/
} else {
int depth = 1;
// ContactComment contactComment = new ContactComment(comments,inquiryId,username,parent);
ContactComment contactComment = createContactCommentRequest.toEntity(inquiryId, username,
nickName, parent, depth);
contactCommentRepository.save(contactComment);
}
}
}