댓글을 추가했을 때 댓글을 적은 사용자의 이미지, 아이디, 댓글내용, 삭제버튼을 표시하고 싶었다
div.video__comments
ul
each comment in comments.reverse()
li.video__comment(data-id=comment.id)
div.video__comment-area
div.video__comment__owner-img
//avatarUrl이 "http"로 시작하면
if `${(comment.owner.avatarUrl).substring(0,4)}` === "http"
img(src=comment.owner.avatarUrl) //img src를 표시
//그게 아니면 (서버에 있는 이미지가 아닐 때, 이미지가 없을 때)
else
img(src="/" + comment.owner.avatarUrl, crossorigin) //지금 오류남
div.video__comment-info
a.video__comment__owner-name(href=`/users/${comment.owner._id}`)
span #{comment.owner.name}
span #{comment.text}
//댓글 주인 id, 로그인 id가 같으면 삭제버튼 표시
if String(comment.owner._id) == String(loggedInUser._id)
span.video__comment-delete(data-id=comment.id) 삭제
else
span No Comments found.
const videoContainer = document.getElementById("videoContainer");
const form = document.getElementById("commentForm");
const deleteBtn = document.querySelectorAll(".video__comment-delete");
const addComment = (text, id, owner) => {
const videoComments = document.querySelector(".video__comments ul");
const newComment = document.createElement("li");
newComment.dataset.id = id;
newComment.className = "video__comment";
//ownerImg추가
const ownerImg = document.createElement("div");
ownerImg.className = "video__comment__owner-img";
const img = document.createElement("img");
if (owner.avatarUrl.substring(0, 4) === "http") {
img.src = owner.avatarUrl;
} else {
img.src = "/" + owner.avatarUrl;
}
//info div 추가
const info = document.createElement("div");
info.className = "video__comment-info";
//ownerName 추가
const ownerName = document.createElement("a");
ownerName.href = `/users/${owner._id}`;
ownerName.className = "video__comment__owner-name";
const ownerNameSpan = document.createElement("span");
ownerNameSpan.innerText = `${owner.name}`;
//text 추가
const span = document.createElement("span");
span.innerText = ` ${text}`;
//remove 추가
const remove = document.createElement("span");
remove.innerText = "삭제";
remove.dataset.id = id;
remove.addEventListener("click", handleDelete);
newComment.appendChild(ownerImg);
ownerImg.appendChild(img);
newComment.appendChild(info);
info.appendChild(ownerName);
ownerName.appendChild(ownerNameSpan);
info.appendChild(span);
newComment.appendChild(remove);
videoComments.prepend(newComment);
};
const handleSubmit = async (event) => {
event.preventDefault();
const textarea = form.querySelector("textarea");
const text = textarea.value;
const videoId = videoContainer.dataset.id;
if (text.trim() === "") {
return;
}
const response = await fetch(`/api/videos/${videoId}/comment`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ text }),
});
if (response.status === 201) {
textarea.value = "";
const { newCommentId, owner } = await response.json();
addComment(text, newCommentId, owner);
}
};
if (form) {
form.addEventListener("submit", handleSubmit);
}
const handleDelete = async (event) => {
//li의 className을 parent로 지정
const parent = event.target.closest(".video__comment");
console.log(parent);
const commentId = parent.dataset.id;
await fetch(`/api/comments/${commentId}`, {
method: "DELETE",
});
parent.remove();
};
deleteBtn.forEach((elm) => elm.addEventListener("click", handleDelete));
export const watch = async (req, res) => {
const { id } = req.params;
const video = await Video.findById(id).populate("owner").populate("comments");
const comments = await Comment.find({ video: id }).populate("owner"); //!!!
if (!video) {
return res.render("404", { pageTitle: "Video not found." });
}
return res.render("watch", { pageTitle: video.title, video, comments });
};
//댓글 생성
export const createComment = async (req, res) => {
const {
session: {
user: { _id },
},
body: { text },
params: { id },
} = req;
const video = await Video.findById(id);
if (!video) {
return res.sendStatus(404);
}
//댓글 생성할 때 : 댓글 내용, 댓글 주인 id, 영상 id
const comment = await Comment.create({
text,
owner: _id,
video: id,
});
//댓글 주인
const owner = await User.findById(comment.owner); //comment_owner
owner.comments.push(comment._id);
owner.save();
video.comments.push(comment._id);
video.save();
return res.status(201).json({ newCommentId: comment._i, owner }); //comment_owner
};
//댓글 삭제
export const deleteComment = async (req, res) => {
const { id } = req.params;
const {
user: { _id },
} = req.session;
const comment = await Comment.findById(id);
if (!comment) {
return res.sendStatus(404);
}
await Comment.findByIdAndDelete(id);
return res.sendStatus(200);
};
import express from "express";
import {
registerView,
createComment,
deleteComment,
} from "../controllers/videoController";
const apiRouter = express.Router();
apiRouter.post("/videos/:id([0-9a-f]{24})/view", registerView);
apiRouter.post("/videos/:id([0-9a-f]{24})/comment", createComment); //댓글 생성
apiRouter.delete("/comments/:id([0-9a-f]{24})", deleteComment); //댓글 삭제
export default apiRouter;
[결과]
[오류 있는거]
[아직 헷갈리는거]
our Escort in Panaji gallery then you can make advance booking for her fellowship by contacting us. We always available for you to fulfil your sensual needs.
I tried your Drift hunters method, it's really helpful for me. Thank you very much!
The basic reason for considering our agency is that you can book highly professional, smart, and bold girls from here. These girls offer you a great amount of physical as well as mental satisfaction. If you want to book any of our Arab Goa Escorts Service ,
These young beautiful Escorts in Paharganj are well-known for their valuable and real-life experience which every men appreciates.
They don't hesitate to become naked in front of our Call Girls in Noida clients. Confidence and passion are in her blood. You can't even feel this is your first time to meet with them. Their sexy bodies easily catch your attention towards them.
As the most well-known escort agency in Jaipur, we allow our clients to choose Jaipur Escort Service by showcasing escort girl profiles online. Offering clients choice is best achieved by showcasing escort profiles in the form of a gallery.
I have never tried this minecraftle feature