Decoupling HTML and JavaScript
Using the DOM model to specify event handlers reduces the degree of coupling between HTML and JavaScript.
Adding the id attribute to an element makes it easier to specify an event handler:
<input type="button" id="some-button" value="Button" />
window.onload = function() {
const btn = document.getElementById("some-button");
btn.onclick = function() {
//TODO
};
};
The onload event occurs when all elements of the document (including images) are ready. There is also a disadvantage to specifying event handlers using the window's onload event.
- You may need to add global attributes (id, class, title) that you didn't need until now.
- Many images in the document may slow down the handler registration. (You can use JQuery to improve this)
This section describes how to remove the handler specified in the HTML attribute and use DOM to specify handlers. We will practice with the view.jsp of the bulletin board.
Attachment link and Attachment delete link
Modify the download link and the delete link as follows.
<div id="detail">
<div id="date-writer-hit">
edited <fmt:formatDate pattern="yyyy.MM.dd HH:mm:ss" value="${regdate }" /> by ${name } hit {hit }
</div>
<div id="article-content">${content }</div>
<div id="file-list" style="text-align: right;">
<c:forEach var="file" items="${attachFileList }" varStatus="status">
<div class="attach-file">
<a href="#" title="${file.filename }" class="download">${file.filename }</a>
<security:authorize access="#email == principal.username or hasRole('ROLE_ADMIN')">
<a href="#" title="${file.attachFileNo }">Del</a>
</security:authorize>
</div>
</c:forEach>
</div>
</div>
Add the following between <script> and </script>.
window.onload = initPage;
function initPage() {
//Download link and the delete link
const file_list = document.getElementById("file-list");
const fileLinks = file_list.getElementsByTagName("a");
for (let i = 0; i < fileLinks.length; i++) {
const fileLink = fileLinks[i];
if (fileLink.className == "download") {
fileLink.onclick = function() {
const attachFileNo = this.title;
const form = document.getElementById("downForm");
form.attachFileNo.value = attachFileNo;
form.submit();
return false;
};
} else {
fileLink.onclick = function() {
const attachFileNo = this.title;
const chk = confirm("Are you sure you want to delete it?");
if (chk === true) {
const form = document.getElementById("deleteAttachFileForm");
form.attachFileNo.value = attachFileNo;
form.submit();
return false;
}
};
}
}
//TODO: Add code here
}//initPage function end
Comment
Modify as follows.
<div id="all-comments">
<c:forEach var="comment" items="${commentList }" varStatus="status">
<div class="comments">
<span class="writer">${comment.name }</span>
<span class="date">${comment.regdate }</span>
<security:authorize access="#comment.email == principal.username or hasRole('ROLE_ADMIN')">
<span class="modify-del">
<a href="#">Modify</a> | <a href="#" title="${comment.commentNo }">Del</a>
</span>
</security:authorize>
<div class="comment-memo">${comment.memo }</div>
<form class="comment-form" action="updateComment" method="post" style="display: none">
<input type="hidden" name="commentNo" value="${comment.commentNo }" />
<input type="hidden" name="boardCd" value="${param.boardCd }" />
<input type="hidden" name="articleNo" value="${param.articleNo }" />
<input type="hidden" name="page" value="${param.page }" />
<input type="hidden" name="searchWord" value="${param.searchWord }" />
<div style="text-align: right;">
<a href="#">Submit</a> | <a href="#">Cancel</a>
</div>
<div>
<textarea class="comment-textarea" name="memo" rows="7" cols="50">${comment.memo }</textarea>
</div>
</form>
</div>
</c:forEach>
</div>
Add the following outside the initPage() function:
function commentUpdate(e) {
const me = getActivatedObject(e);
const form = me.parentNode;
while (form.className != "comment-form") {
form = form.parentNode;
}
form.submit();
return false;
}
function modifyCommentToggle(e) {
const me = getActivatedObject(e);
const comments = me.parentNode;
while (comments.className != "comments") {
comments = comments.parentNode;
}
const div = comments.getElementsByTagName("div")[0];//Comment p
const form = comments.getElementsByTagName("form")[0];//Comment form
if (div.style.display) {
div.style.display = '';
form.style.display = 'none';
} else {
div.style.display = 'none';
form.style.display = '';
}
return false;
}
/*
Head First Ajax
*/
function getActivatedObject(e) {
let obj;
if (!e) {
//IE Old version
obj = window.event.srcElement;
} else if (e.srcElement) {
//IE 7
obj = e.srcElement;
} else {
//DOM Level 2
obj = e.target;
}
return obj;
}
Add the following to initPage().
const allComments = document.getElementById("all-comments");
const divs = allComments.getElementsByTagName("div");
for (i = 0; i < divs.length; i++) {
if (divs[i].className == "comments") {
const comments = divs[i];
const spans = comments.getElementsByTagName("span");
for (let j = 0; j < spans.length; j++) {
if (spans[j].className === "modify-del") {
const md = spans[j];
const commentModifyLink = md.getElementsByTagName("a")[0];//Modify link
commentModifyLink.onclick = modifyCommentToggle;
const commentDelLink = md.getElementsByTagName("a")[1];//Delete link
commentDelLink.onclick = function() {
const commentNo = this.title;
const chk = confirm("Are you sure you want to delete it?");
if (chk === true) {
const form = document.getElementById("deleteCommentForm");
form.commentNo.value = commentNo;
form.submit();
return false;
}
};
}
//Modify link in form
const form = comments.getElementsByTagName("form")[0];
const div = form.getElementsByTagName("div")[0];
commentModifyLink = div.getElementsByTagName("a")[0];
commentModifyLink.onclick = commentUpdate;
//Cancel link in form
const cancelLink = div.getElementsByTagName("a")[1];
cancelLink.onclick = modifyCommentToggle;
}
}
}
Next article link and Prev article link
Modify as follows.
<div id="next-prev">
<c:if test="${nextArticle != null }">
<p>Next Article : <a href="#" title="${nextArticle.articleNo }">${nextArticle.title } </a></p>
</c:if>
<c:if test="${prevArticle != null }">
<p>Prev Article : <a href="#" title="${prevArticle.articleNo }">${prevArticle.article.title }</a></p>
</c:if>
</div>
Add the following to initPage().
//Next Article link, Prev Article link
const nextPrev = document.getElementById("next-prev");
links = nextPrev.getElementsByTagName("a");
for (i = 0; i < links.length; i++) {
links[i].onclick = function() {
const form = document.getElementById("viewForm");
form.articleNo.value = this.title;
form.submit();
return false;
};
}
Modify/Del/Next Article/Prev Article/List/New Article Button
There are two view-menu classes surrounding buttons, so we need to modify both.
<div class="view-menu" ..>
<security:authorize access="#email == principal.username or hasRole('ROLE_ADMIN')">
<div class="fl">
<input type="button" value="Modify" class="goModify" />
<input type="button" value="Del" class="goDelete" />
</div>
</security:authorize>
<div class="fr">
<c:if test="${nextArticle != null }">
<input type="button" value="Next Article" title="${nextArticle.articleNo }" class="next-article" />
</c:if>
<c:if test="${prevArticle != null }">
<input type="button" value="Prev Article" title="${prevArticle.articleNo }" class="prev-article" />
</c:if>
<input type="button" value="List" class="goList" />
<input type="button" value="New Article" class="goWrite" />
</div>
</div>
Add the following to initPage().
//Modify Button
const modifyBtns = document.getElementsByClassName("goModify");
i = modifyBtns.length;
while (i--) {
modifyBtns[i].onclick = function() {
const form = document.getElementById("modifyForm");
form.submit();
};
}
//Del Button
const deleteBtns = document.getElementsByClassName("goDelete");
i = deleteBtns.length;
while (i--) {
deleteBtns[i].onclick = function() {
const chk = confirm('Are you sure you want to delete it?');
if (chk === true) {
const form = document.getElementById("delForm");
form.submit();
}
};
}
//Next Article Button
const nextArticleBtns = document.getElementsByClassName("next-article");
i = nextArticleBtns.length;
while (i--) {
nextArticleBtns[i].onclick = function() {
const form = document.getElementById("viewForm");
form.articleNo.value = this.title;
form.submit();
};
}
//Prev Article Button
const prevArticleBtns = document.getElementsByClassName("prev-article");
i = prevArticleBtns.length;
while (i--) {
prevArticleBtns[i].onclick = function() {
const form = document.getElementById("viewForm");
form.articleNo.value = this.title;
form.submit();
};
}
//List Button
const listBtns = document.getElementsByClassName("goList");
i = listBtns.length
while (i--) {
listBtns[i].onclick = function() {
const form = document.getElementById("listForm");
form.submit();
};
}
//New Article Button
const writeBtns = document.getElementById("goWrite");
i = writeBtns.length;
while(i--) {
writeBtns[i].onclick = function() {
const form = document.getElementById("writeForm");
form.submit();
};
}
Title link, Page move link, New Article Button
Modify as follows.
<table id="list-table" class="bbs-table">
<tr>
<th style="width: 60px">NO</th>
<th>TITLE</th>
<th style="width: 84px;">DATE</th>
<th style="width: 60px;">HIT</th>
</tr>
<!-- List items start -->
<c:forEach var="article" items="${list }" varStatus="status">
<tr>
<td style="text-align: center;">
<c:choose>
<c:when test="${param.articleNo == article.articleNo }">
<img src="/resources/images/arrow.gif" alt="You are reading this" />
</c:when>
<c:otherwise>
${listItemNo - status.index }
</c:otherwise>
</c:choose>
</td>
<td>
<a href="#" title="${article.articleNo }">${article.title }</a>
<c:if test="${article.attachFileNum > 0 }">
<img src="/resources/images/attach.png" alt="Attach File" style="vertical-align: middle;" />
</c:if>
<c:if test="${article.commentNum > 0 }">
<span class="bbs-strong">[${article.commentNum }]</span>
</c:if>
</td>
<td style="text-align: center;">
<fmt:formatDate pattern="yyyy.MM.dd" value="${article.regdate }" />
</td>
<td style="text-align: center;">${article.hit }</td>
</tr>
</c:forEach>
<!-- List items end -->
</table>
<div id="paging">
<c:if test="${prevPage > 0 }">
<a href="#" title="${prevPage }">[Prev]</a>
</c:if>
<c:forEach var="i" begin="${firstPage }" end="${lastPage }">
<c:choose>
<c:when test="${param.page == i }">
<span class="bbs-strong">${i }</span>
</c:when>
<c:otherwise>
<a href="#" title="${i }">${i }</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${nextPage > 0 }">
<a href="#" title="${nextPage }">[Next]</a>
</c:if>
</div>
<div id="list-menu">
<input type="button" value="New" />
</div>
Add the following to initPage().
//Title links in detail view
const listTable = document.getElementById("list-table");
links = listTable.getElementsByTagName("a");
for (i = 0; i < links.length; i++) {
links[i].onclick = function() {
const form = document.getElementById("viewForm");
form.articleNo.value = this.title;
form.submit();
return false;
};
}
//Paging
const paging = document.getElementById("paging");
links = paging.getElementsByTagName("a");
for (i = 0; i < links.length; i++) {
links[i].onclick = function() {
const form = document.getElementById("listForm");
form.page.value = this.title;
form.submit();
return false;
};
}
//New Article button
const listMenu = document.getElementById("list-menu");
writeBtn = listMenu.getElementsByTagName("input")[0];
writeBtn.onclick = function() {
const form = document.getElementById("writeForm");
form.submit();
};
Attachment link and Attachment delete link (jQuery)
Let's change the JavaScript DOM example to use jQuery.
Download the latest version of jQuery from https://jquery.com/ and put the jQuery file in the /js folder. Add the following between <head> and </head> of view.jsp.
<script src="/resources/js/jquery.js"></script>
The HTML code has nothing to change.
<div id="detail">
<div id="date-writer-hit">
edited <fmt:formatDate pattern="yyyy.MM.dd HH:mm:ss" value="${regdate }" /> by ${name } hit {hit }
</div>
<div id="article-content">${content }</div>
<div id="file-list" style="text-align: right;">
<c:forEach var="file" items="${attachFileList }" varStatus="status">
<div class="attach-file">
<a href="#" title="${file.filename }" class="download">${file.filename }</a>
<security:authorize access="#email == principal.username or hasRole('ROLE_ADMIN')">
<a href="#" title="${file.attachFileNo }">Del</a>
</security:authorize>
</div>
</c:forEach>
</div>
</div>
Comment out all the existing contents of the JavaScript, add the following code.
$(document).ready(function() {
$('#file-list a.download').click(function(e) {
e.preventDefault();
const filename = this.title;
$('#downForm input[name*=filename]').val(filename);
$('#downForm').submit();
});
$('#file-list a:not(.download)').click(function(e) {
e.preventDefault();
const chk = confirm("Are you sure you want to delete it?");
if (chk === true) {
const attachFileNo = this.title;
$('#deleteAttachFileForm input[name*=attachFileNo]').val(attachFileNo);
$('#deleteAttachFileForm').submit();
}
});
});
Comment(jQuery)
Modify as follows.
<div id="all-comments">
<c:forEach var="comment" items="${commentList }">
<div class="comments">
<span class="writer">${comment.username }</span>
<span class="date">${comment.regdate }</span>
<c:if test="${user.username == comment.username }" >
<span class="modify-del">
<a href="#" class="comment-modify-link">Modify</a> |
<a href="#" class="comment-delete-link" title="${comment.commentNo }">Del</a>
</span>
</c:if>
<div class="comment-memo">${comment.memo }</div>
<form class="comment-form" action="updateComment" method="post" style="display: none">
<input type="hidden" name="commentNo" value="${comment.commentNo }" />
<input type="hidden" name="boardCd" value="${param.boardCd }" />
<input type="hidden" name="articleNo" value="${param.articleNo }" />
<input type="hidden" name="page" value="${param.page }" />
<input type="hidden" name="searchWord" value="${param.searchWord }" />
<div style="text-align: right;">
<a href="#" class="comment-modify-submit-link">Submit</a> | <a href="#" class="comment-modify-cancel-link">Cancel</a>
</div>
<div>
<textarea class="comment-textarea" name="memo" rows="7" cols="50">${comment.memo }</textarea>
</div>
</form>
</div>
</c:forEach>
</div>
Add the following to $(document).ready(function() {} function.
//Comments
$('.comments').click(function(e) {
e.preventDefault();
if ($(e.target).is('.comment-modify-link')) {
const $form = $(e.target).parent().parent().find('.comment-form');
const $div = $(e.target).parent().parent().find('.comment-memo');
if ($form.is(':hidden') === true) {
$form.show();
$div.hide();
} else {
$form.hide();
$div.show();
}
} else if ($(e.target).is('.comment-modify-cancel-link')) {
const $form = $(e.target).parent().parent().parent().find('.comment-form');
const $div = $(e.target).parent().parent().parent().find('.comment-memo');
if ($form.is(':hidden') === true) {
$form.show();
$div.hide();
} else {
$form.hide();
$div.show();
}
} else if ($(e.target).is('.comment-modify-submit-link')) {
const $form = $(e.target).parent().parent().parent().find('.comment-form');
$form.submit();
} else if ($(e.target).is('.comment-delete-link')) {
const chk = confirm('Are you sure you want to delete it?');
if (chk === false) {
return;
}
const $commentNo = $(e.target).attr('title');
$('#deleteCommentForm input[name*=commentNo]').val($commentNo);
$('#deleteCommentForm').submit();
}
});
Prev Article link and Next Article link (jQuery)
The HTML code has nothing to change.
<div id="next-prev">
<c:if test="${nextArticle != null }">
<p>Next Article : <a href="#" title="${nextArticle.articleNo }">${nextArticle.title }</a></p>
</c:if>
<c:if test="${prevArticle != null }">
<p>Prev Article : <a href="#" title="${prevArticle.articleNo }">${prevArticle.title }</a></p>
</c:if>
</div>
Add the following to $(document).ready(function() {} function.
$('#next-prev a').click(function(e) {
e.preventDefault();
const articleNo = this.title;
$('#viewForm input[name*=articleNo]').val(articleNo);
$('#viewForm').submit();
});
Modify/Del/Next Article/Prev Article/List/New Article Button (jQuery)
The HTML code has nothing to change.
<div class="view-menu" .. >
<security:authorize access="#email == principal.username or hasRole('ROLE_ADMIN')">
<div class="fl">
<input type="button" value="Modify" class="goModify" />
<input type="button" value="Del" class="goDelete" />
</div>
</security:authorize>
<div class="fr">
<c:if test="${nextArticle != null }">
<input type="button" value="Next Article" title="${nextArticle.articleNo }" class="next-article" />
</c:if>
<c:if test="${prevArticle != null }">
<input type="button" value="Prev Article" title="${prevArticle.articleNo }" class="prev-article" />
</c:if>
<input type="button" value="List" class="goList" />
<input type="button" value="New Article" class="goWrite" />
</div>
</div>
Add the following to $(document).ready(function() {} function.
//Modify Button
$('.goModify').click(function() {
$('#modifyForm').submit();
});
//Del Button
$('.goDelete').click(function() {
const chk = confirm('Are you sure you want to delete it?');
if (chk === true) {
$('#delForm').submit();
}
});
//Next Article Button
$('.next-article').click(function() {
const articleNo = this.title;
$('#viewForm input[name*articleNo]').val(articleNo);
$('#viewForm').submit();
});
//Prev Article Button
$('.prev-article').click(function() {
const articleNo = this.title;
$('#viewForm input[name*articleNo]').val(articleNo);
$('#viewForm').submit();
});
//List Button
$('.goList').click(function() {
$('#listForm').submit();
});
//New Article Button
$('.goWrite').click(function() {
$('#writeForm').submit();
});
Title link, Page move links, New Article Button (jQuery)
The relevant code is the same as before.
<table id="list-table" class="bbs-table">
<tr>
<th style="width: 60px">NO</th>
<th>TITLE</th>
<th style="width: 84px;">DATE</th>
<th style="width: 60px;">HIT</th>
</tr>
<!-- List items start -->
<c:forEach var="article" items="${list }" varStatus="status">
<tr>
<td style="text-align: center;">
<c:choose>
<c:when test="${param.articleNo == article.articleNo }">
<img src="/resources/images/arrow.gif" alt="You are reading this" />
</c:when>
<c:otherwise>
${listItemNo - status.index }
</c:otherwise>
</c:choose>
</td>
<td>
<a href="#" title="${article.articleNo }">${article.title }</a>
<c:if test="${article.attachFileNum > 0 }">
<img src="/resources/images/attach.png" alt="Attach File" style="vertical-align: middle;" />
</c:if>
<c:if test="${article.commentNum > 0 }">
<span class="bbs-strong">[${article.commentNum }]</span>
</c:if>
</td>
<td style="text-align: center;">
<fmt:formatDate pattern="yyyy.MM.dd" value="${article.regdate }" />
</td>
<td style="text-align: center;">${article.hit }</td>
</tr>
</c:forEach>
<!-- List items end -->
</table>
<div id="paging">
<c:if test="${prevPage > 0 }">
<a href="#" title="${prevPage }">[Prev]</a>
</c:if>
<c:forEach var="i" begin="${firstPage }" end="${lastPage }">
<c:choose>
<c:when test="${param.page == i }">
<span class="bbs-strong">${i }</span>
</c:when>
<c:otherwise>
<a href="#" title="${i }">${i }</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${nextPage > 0 }">
<a href="#" title="${nextPage }">[Next]</a>
</c:if>
</div>
<div id="list-menu">
<input type="button" value="New Article" />
</div>
Add the following to $(document).ready(function() {} function.
//Title links in Detailed view
$('#list-table a').click(function(e) {
e.preventDefault();
const articleNo = this.title;
$('#viewForm input[name*articleNo]').val(articleNo);
$('#viewForm').submit();
});
//Paging
$('#paging a').click(function(e) {
e.preventDefault();
const page = this.title;
$('#listForm input[name*=page]').val(page);
$('#listForm').submit();
});
//New Article Button
$('#list-menu input').click(function() {
$('#writeForm').submit();
});
It is up to you to use pure JavaScript or jQuery.
