I'm implementing a bulletin board comment function, but I'm blocked from looking up comments.
I made a recursive function to make the big comments appear under the comments, but I keep getting errors, but I don't know where the problem is.
window.onload = () => {
findAllComment();
}
// 전체 댓글 조회
function findAllComment() {
const postId = [[ ${post.id} ]];
const accountId = [[ ${account.id} ]]
$.ajax({
url: `/api/posts/${postId}/comments`,
beforeSend: function (xhr) {
xhr.setRequestHeader(header, token);
},
type: 'get',
dataType: 'json',
async: false,
success: function (response) {
console.log(response);
// 1. 조회된 데이터가 없는 경우
if (!response.result.data.length) {
return false;
}
// 2. 렌더링 할 HTML을 저장할 변수
let commentHtml = '';
// 3. 댓글 HTML 추가
response.result.data.forEach(row => {
commentHtml += `
<div class="card py-0 mt-3">
<div class="card-header bg-light">
<span class="comment-writer"><span class="card-text">${row.account.nickname}</span></span>
<a sec:authorize="isAuthenticated()" th:if="${row.account.id == accountId}">
<a class="comment-delete" onclick="deleteComment(${row.id});"><i class="bi bi-trash3"></i><span class="card-text ml-1">삭제</span></a>
<a class="comment-edit" onclick="findEditComment(${row.id});"><i class="fa fa-pencil"></i><span class="card-text ml-1">수정</span></a>
</a>
<a class="comment-reply" onclick="findReplyComment(${row.id})"><i class="fa fa-comment fa"></i><span class="card-text ml-1">답글</span></a>
<span class="date" id="commentDate">${dayjs(row.createdDateTime).format('YYYY-MM-DD HH:mm')}</span>
</div>
<div class="card-body">
<span class="comment-content"><span class="card-text">${row.content}</span></span>
</div>
</div>
<!--/* 답글 뷰 */-->
<div id="cm_reply_view${row.id}"></div>
<!--/* 댓글 수정 뷰 */-->
<div id="cm_edit_view${row.id}"></div>
<!--/* 댓글 답글 작성 뷰 */-->
<div id="cm_createReply_view${row.id}"></div>
`;
if (row.children.length) {
row.children.forEach(childRow => {
findChildComment(row.id, childRow);
})
}
})
// 4. class가 "cm_list"인 요소를 찾아 HTML을 렌더링
document.querySelector('.cm_list').innerHTML = commentHtml;
},
error: function (request, status, error) {
console.log(error)
}
})
}
// 답글 조회
function findChildComment(parentId, child) {
var idForInnerHtml = '#cm_reply_view' + parentId;
const accountId = [[ ${account.id} ]];
let commentHtml = `
<div class="card py-0 mt-3">
<div class="card-header bg-light">
<span class="comment-writer"><span class="card-text">${child.account.nickname}</span></span>
<a sec:authorize="isAuthenticated()" th:if="${child.account.id == accountId}">
<a class="comment-delete" onclick="deleteComment(${child.id});"><i class="bi bi-trash3"></i><span class="card-text ml-1">삭제</span></a>
<a class="comment-edit" onclick="findEditComment(${child.id});"><i class="fa fa-pencil"></i><span class="card-text ml-1">수정</span></a>
</a>
<a class="comment-reply" onclick="findReplyComment(${child.id})"><i class="fa fa-comment fa"></i><span class="card-text ml-1">답글</span></a>
<span class="date" id="commentDate">${dayjs(child.createdDateTime).format('YYYY-MM-DD HH:mm')}</span>
</div>
<div class="card-body">
<span class="comment-content"><span class="card-text">${child.content}</span></span>
</div>
</div>
<!--/* 답글 뷰 */-->
<div id="cm_reply_view${child.id}"></div>
<!--/* 댓글 수정 뷰 */-->
<div id="cm_edit_view${child.id}"></div>
<!--/* 댓글 답글 작성 뷰 */-->
<div id="cm_createReply_view${child.id}"></div>
`;
if (child.children.length) {
child.children.forEach(childRow => {
findChildComment(child.id, childRow);
})
}
document.querySelector(idForInnerHtml).innerHTML = commentHtml;
}
"Uncaught TypeError: Cannot set properties of null (setting 'innerHTML')" error occurs at "document.querySelector(idForInnerHtml).innerHTML = commentHtml;" last line of 'findChildComment ' method.
I checked through logs that <id="cm_reply_view${row.id}"> and <var idForInnerHtml = '#cm_reply_view' + parentId;> has same value, but I don't know which part is the problem. If anyone knows, please let me know, thank you.
The problem is that you are assigning the HTML after having performed the recursion. Yet the recursive calls need the HTML with the parent div
to already be present in the document. So you need to reverse the logic a bit.
Here are some changes to the code that should make it work:
In the success
callback, in step 3, first finish the forEach
loop before making recursive calls:
response.result.data.forEach(row => {
commentHtml += /* Your HTML Comes here */ ;
}); // Finish the top HTML first, then load the collected HTML into the document
document.querySelector('.cm_list').innerHTML = commentHtml;
// And only now perform the recursion, which needs that HTML
// to already be present in the document.
response.result.data.forEach(row => {
if (row.children.length) {
row.children.forEach(childRow => {
findChildComment(row.id, childRow);
})
}
})
A similar change is needed in findChildComment
:
let commentHtml = /* Your HTML comes here */;
// Again: first assign the HTML that you need for the recursive calls
document.querySelector(idForInnerHtml).innerHTML = commentHtml;
// ... and then make the recursive calls:
if (child.children.length) {
child.children.forEach(childRow => {
findChildComment(child.id, childRow);
})
}