저번 글에 이어서
오늘은 팀원분이 완성해두신 상세페이지 -> 리뷰 작성 기능에 유효성 검사를 추가해보려고 한다.
우선 어떤 식으로 유효성 검사를 구현할지 먼저 생각을 좀 해봤다.
1. 댓글 텍스트 수
2. 캡스락 keyup 여부
3. 한/영 여부
인데, 사실 한/영 여부는 불필요하다고 생각했고, 댓글 텍스트 수도 실제로는 제한이 없기 때문에
2. 캡스락 keyup 여부를 구현하기로 했다.
const usernameInput = document.getElementById("username");
usernameInput.addEventListener("keyup", function (event) {
if (event.getModifierState("CapsLock")) {
// CapsLock이 켜져 있을 때
document.getElementById("capslock-warning").innerText = "CapsLock 이 활성화 되어있는 상태입니다";
} else {
// CapsLock이 꺼져 있을 때
document.getElementById("capslock-warning").innerText = "";
}
});
사실 이벤트 리스너에 대해 구글링을 하다 keyup 게시글도 우연히 보게 되어서 어떻게 구현해야 할지 대충
감이 잡혀있는 상태여서 비교적 쉽게 (?) 구현할 수 있었다.
무슨 기능이 있고, 어떻게 쓰이며, 어디에 들어가야 할지만 안다면 시간이 좀 걸릴 뿐 불가능하진 않은 것 같다.
그래서 많이 검색해보고, 구현해보고, 보지만 말고 직접 해보는게 중요한 것 같다. (개인적 견해입니다)
단점은, 아직 내 코드에 대해 시원하게 풀이를 하지 못한다는 점? 그리고 알고리즘에 약하다는 점....
익숙해지겠지?
username 인풋에서 capsLock 을 누를 시 innertext 로 문구를 띄움.
유효성 검사만 구현하려고 하다보니 시간이 꽤 남아서 팀원분들께 " 수정할거 없나요, 저 조금 더 고생해도 되는데 "
라고 하니
수정하는 버튼 누르면 아예 비밀번호 입력이랑 수정할 내용을 한꺼번에 모달창으로 띄워도 괜찮을 것 같다는 생각이 들었어요!
라는 아이디어를 제시 해주셨다. ( 당시엔 이게 나의 하루를 잡아먹을거라고는 전혀 생각하지 못했다. )
기존 코드는 수정하기 버튼을 눌렀을 때 alert 을 띄워 패스워드를 입력하게 하고, 패스워드가 일치한다면
새로운 내용을 작성하게 하고, 작성 후 확인 버튼을 누르면 댓글창에 반영이 되는 방식이였다.
기능 구현에 의의를 둔다면 이것도 상관없긴 하지만, 조금 더 깔끔하게? 하고 싶으셨던 모양이다!
그리고 또 하나의 문제는 alert 은 비밀번호를 **** 표시 할 수 없다는 점.
여러모로 모달창을 띄우는 편이 깔끔하기도 하고, 기능적으로도 괜찮을 것 같다는 생각이 들었다.
<!-- 모달 창 (댓글수정) -->
<div id="modal" class="modal">
<div class="modal-content">
<div class="modal-input">
<input id="passwordInput" type="password" placeholder="패스워드를 입력하세요.">
<textarea id="commentInput" placeholder="수정하실 내용을 입력하세요."></textarea>
</div>
<div class="modalbtn">
<button id="submitBtn"><span style="color: white;">확인</span></button>
<button id="cancelBtn"><span style="color: white;">취소</span></button>
</div>
</div>
</div>
스크립트 작성에 앞서 우선 html 에 모달창을 만들어줬다.
비밀번호 input, 본문이 들어갈 input, 확인 버튼, 취소 버튼으로 이루어져 있다.
display: none;
/* 기본적으로는 숨김 */
position: fixed;
/* 고정 위치 */
z-index: 1;
/* 다른 요소 위에 표시 */
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
/* 스크롤 가능 */
background-color: rgba(0, 0, 0, 0.4);
/* 배경색과 투명도 */
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
/* 중앙 정렬 */
padding: 60px;
border: 1px solid #888;
width: 80%;
/* 모달창 너비 */
}
#passwordInput {
margin-bottom: 10px;
border: 1px solid #ccc;
/* 테두리 스타일 지정 */
padding: 5px;
/* 안쪽 여백 지정 */
border-radius: 4px;
/* 테두리 모서리를 둥글게 만듦 */
}
#commentInput {
width: 1215px;
height: 85;
border: 1px solid #ccc;
/* 테두리 스타일 지정 */
padding: 5px;
/* 안쪽 여백 지정 */
border-radius: 4px;
/* 테두리 모서리를 둥글게 만듦 */
}
.modalbtn {
float: right;
padding-top: 20px;
}
#submitBtn {
background-color: blue;
}
#cancelBtn {
background-color: red;
}
모달창은 수정하기 버튼을 눌렀을 때만 나와야 하기 때문에 display : none; 으로 기본적으로는 숨김 상태여야 한다.
그리고 팝업창 느낌으로 다른 요소 위에 표시하기 위해 z-index: 1; 을 사용했다.
모달창이 떠있는 중에도 페이지를 스크롤 할 수 있게 overflow : auto; 를 사용했다.
완성된 모달창
// 댓글 수정 (모달)
const editComment = (e) => {
const commentBox = e.target.parentNode.parentNode.parentNode.parentNode;
const commentOnStorage = getComments(movieId);
const modal = document.getElementById("modal");
const passwordInput = document.getElementById("passwordInput");
const commentInput = document.getElementById("commentInput");
const submitBtn = document.getElementById("submitBtn");
const cancelBtn = document.getElementById("cancelBtn");
modal.style.display = "block"; // 모달창 열기
// 모달창 닫기
const closeModal = () => {
modal.style.display = "none";
passwordInput.value = "";
commentInput.value = "";
};
// 확인 버튼 클릭 시
submitBtn.onclick = () => {
const passwordEditTry = passwordInput.value;
commentOnStorage.forEach((element) => {
if (commentBox.getAttribute("id") === String(element.Id)) {
if (passwordEditTry === element.Password) {
element.Review = commentInput.value;
saveComments(movieId, commentOnStorage);
alert("저장되었습니다.");
closeModal(); // 모달 닫기
location.reload(); // 페이지 새로고침
} else {
alert("비밀번호가 일치하지 않습니다.");
closeModal(); // 모달 닫기
}
}
});
};
// 취소 버튼 클릭 시
cancelBtn.onclick = () => {
closeModal(); // 모달 닫기
};
// 모달 외부 클릭 시 닫기
window.onclick = (event) => {
if (event.target === modal) {
closeModal(); // 모달 닫기
}
};
};
const editBtn = document.querySelectorAll(".edit");
editBtn.forEach((element) => element.addEventListener("click", editComment));
각각의 댓글에는 수정 버튼이 존재하고, 수정 버튼을 클릭하면 만들어둔 모달 창이 나오게 하는 코드다.
댓글을 작성했을 때 기입해둔 패스워드와 입력한 패스워드가 일치하고, 수정할 본문을 작성한 후 확인 버튼을 누르면
댓글이 수정되고, 모달 창이 닫히며, 페이지가 로드되어 새로고침 하지 않아도 자동으로 수정된 댓글이 반영된다.
비밀번호가 일치하지 않으면 "비밀번호가 일치하지 않습니다. " 라는 alert 과 함께 모달창이 닫혀버리고, 댓글은 수정되지 않는다.
수정하기 옆 삭제하기 버튼 클릭 시, 수정하기와 마찬가지로 모달창을 띄워 패스워드를 입력하게 끔 구현했고,
댓글 작성 시 기입한 패스워드와 일치한다면 "삭제되었습니다" alert 과 함께 페이지가 로드되고, 댓글이 삭제된다.
else -> 비밀번호가 일치하지 않다면, "비밀번호가 일치하지 않습니다." alert 과 함께 모달창이 닫힌다.
<!-- 모달 창 (댓글삭제) -->
<div id="delmodal" class="delmodal">
<div class="delmodal-content">
<span class="close">×</span>
<p style="text-align: center;">패스워드를 입력해주세요.</p>
<div class="delbtn">
<input type="password" id="delpasswordInput" />
<button id="delconfirmBtn">확인</button>
</div>
</div>
</div>
댓글삭제 모달창 html
.delmodal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
}
.delmodal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#delpasswordInput {
border: 1px solid #ccc;
/* 테두리 스타일 지정 */
padding: 5px;
/* 안쪽 여백 지정 */
border-radius: 4px;
/* 테두리 모서리를 둥글게 만듦 */
}
.delbtn {
margin-left: 500px;
margin-top: 10px;
}
댓글삭제 모달창 css
const modal = document.getElementById("delmodal");
const confirmBtn = document.getElementById("delconfirmBtn");
const passwordInput = document.getElementById("delpasswordInput");
const deleteComment = (event) => {
const li = event.target.parentElement.parentElement.parentElement.parentElement;
let cancelSwitch = Boolean;
commentDrawn.forEach((element) => {
if (li.getAttribute("id") === String(element.Id)) {
modal.style.display = "block";
confirmBtn.onclick = () => {
const passwordTry = passwordInput.value;
if (passwordTry === element.Password) {
cancelSwitch = true;
li.remove();
const newComments = commentDrawn.filter(
(element) => element.Id !== li.getAttribute("id")
);
saveComments(movieId, newComments);
alert("삭제되었습니다.");
location.reload();
} else {
cancelSwitch = false;
alert("비밀번호가 일치하지 않습니다.");
}
modal.style.display = "none";
};
modal.querySelector(".close").onclick = () => {
modal.style.display = "none";
cancelSwitch = false;
alert("취소되었습니다.");
};
}
});
};
const deleteBtn = document.querySelectorAll(".delete");
deleteBtn.forEach((element) =>
element.addEventListener("click", deleteComment)
);
댓글삭제 모달창 script
기본중의 기본이지만, 수정 모달창과, 삭제 모달창의 id, class 값을 부여할 때 중복되지 않게 조심해야 한다..
(생각없이 작성하다가 id 값이 똑같은걸 못 찾고 한 참을 헤맴)
3일을 쉬어서 뇌가 리셋이 된 건 아닐까, 하고 불안했는데 오히려 조금 쉬고 오니 머리가 더 잘 돌아가는 느낌이네.
오놀은 진짜 많이 성장했다. 많이 쳐보고 경험치 많이 쌓자.