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() {
  var 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

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
  var file_list = document.getElementById("file-list");
  var fileLinks = file_list.getElementsByTagName("a");
  
  for (var i = 0; i < fileLinks.length; i++) {
    var fileLink = fileLinks[i];
    if (fileLink.className == "download") {
      fileLink.onclick = function() {
        var attachFileNo = this.title;
        var form = document.getElementById("downForm");
        form.attachFileNo.value = attachFileNo;
        form.submit();
        return false;
      };
    } else {
      fileLink.onclick = function() {
        var attachFileNo = this.title;
        var chk = confirm("Are you sure you want to delete it?");
        if (chk === true) {
          var form = document.getElementById("deleteAttachFileForm");
          form.attachFileNo.value = attachFileNo;
          form.submit();
          return false;
        }
      };
    }
  }
  //TODO: Add code here
  
}//initPage function end

Comment

Comments

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) {
  var me = getActivatedObject(e);
  var form = me.parentNode;
  while (form.className != "comment-form") {
    form = form.parentNode;
  }
  form.submit();
  return false;
}
function modifyCommentToggle(e) {
  var me = getActivatedObject(e);
  var comments = me.parentNode;
  while (comments.className != "comments") {
    comments = comments.parentNode;
  }
  var div = comments.getElementsByTagName("div")[0];//Comment p
  var 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) {
  var 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().

var allComments = document.getElementById("all-comments");
var divs = allComments.getElementsByTagName("div");

for (i = 0; i < divs.length; i++) {
  if (divs[i].className == "comments") {
    var comments = divs[i];
    var spans = comments.getElementsByTagName("span");
    for (var j = 0; j < spans.length; j++) {
      if (spans[j].className === "modify-del") {
        var md = spans[j];
        var commentModifyLink = md.getElementsByTagName("a")[0];//Modify link
        commentModifyLink.onclick = modifyCommentToggle;
        var commentDelLink = md.getElementsByTagName("a")[1];//Delete link
        commentDelLink.onclick = function() {
          var commentNo = this.title;
          var chk = confirm("Are you sure you want to delete it?");
          if (chk === true) {
            var form = document.getElementById("deleteCommentForm");
            form.commentNo.value = commentNo;
            form.submit();
            return false;
           }
         };
      }
      //Modify link in form
      var form = comments.getElementsByTagName("form")[0];
      var div = form.getElementsByTagName("div")[0];
      commentModifyLink = div.getElementsByTagName("a")[0];
      commentModifyLink.onclick = commentUpdate;
      //Cancel link in form
      var cancelLink = div.getElementsByTagName("a")[1];
      cancelLink.onclick = modifyCommentToggle;
    }
  }  
}

Next article link and Prev article link

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
var nextPrev = document.getElementById("next-prev");
links = nextPrev.getElementsByTagName("a");
for (i = 0; i < links.length; i++) {
  links[i].onclick = function() {
    var form = document.getElementById("viewForm");
    form.articleNo.value = this.title;
    form.submit();
    return false;  	
  };
}

Modify/Del/Next Article/Prev Article/List/New Article Button

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
var modifyBtns = document.getElementsByClassName("goModify");
i = modifyBtns.length;
while (i--) {
  modifyBtns[i].onclick = function() {
    var form = document.getElementById("modifyForm");
    form.submit();
  };
}
//Del Button
var deleteBtns = document.getElementsByClassName("goDelete");
i = deleteBtns.length;
while (i--) {
  deleteBtns[i].onclick = function() {
    var chk = confirm('Are you sure you want to delete it?');
    if (chk === true) {
      var form = document.getElementById("delForm");
      form.submit();
    }
  };
}
//Next Article Button
var nextArticleBtns = document.getElementsByClassName("next-article");
i = nextArticleBtns.length;
while (i--) {
  nextArticleBtns[i].onclick = function() {
    var form = document.getElementById("viewForm");
    form.articleNo.value = this.title;
    form.submit();
  };
}
//Prev Article Button
var prevArticleBtns = document.getElementsByClassName("prev-article");
i = prevArticleBtns.length;
while (i--) {
  prevArticleBtns[i].onclick = function() {
    var form = document.getElementById("viewForm");
    form.articleNo.value = this.title;
    form.submit();
  };
}
//List Button
var listBtns = document.getElementsByClassName("goList");
i = listBtns.length
while (i--) {
  listBtns[i].onclick = function() {
    var form = document.getElementById("listForm");
    form.submit();
  };
}  
//New Article Button
var writeBtns = document.getElementById("goWrite");
i = writeBtns.length;
while(i--) {
  writeBtns[i].onclick = function() {
    var form = document.getElementById("writeForm");
    form.submit();
  };
}

Title link, Page move link, New Article Button

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
var listTable = document.getElementById("list-table");
links = listTable.getElementsByTagName("a");
for (i = 0; i < links.length; i++) {
  links[i].onclick = function() {
    var form = document.getElementById("viewForm");
    form.articleNo.value = this.title;
    form.submit();
    return false;
  };
}
//Paging
var paging = document.getElementById("paging");
links = paging.getElementsByTagName("a");
for (i = 0; i < links.length; i++) {
  links[i].onclick = function() {
    var form = document.getElementById("listForm");
    form.page.value = this.title;
    form.submit();
    return false;
  };
}
//New Article button
var listMenu = document.getElementById("list-menu");
writeBtn = listMenu.getElementsByTagName("input")[0];
writeBtn.onclick = function() {
  var 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-3.3.1.min.js"></script>

Attachment link and Attachment delete link

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();
    var filename = this.title;
    $('#downForm input[name*=filename]').val(filename);
    $('#downForm').submit();
  });
  $('#file-list a:not(.download)').click(function(e) {
    e.preventDefault();
    var chk = confirm("Are you sure you want to delete it?");
    if (chk === true) {
      var attachFileNo = this.title;
      $('#deleteAttachFileForm input[name*=attachFileNo]').val(attachFileNo);
      $('#deleteAttachFileForm').submit();
    }
  });
});

Comment(jQuery)

Comments

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')) {
    var $form = $(e.target).parent().parent().find('.comment-form');
    var $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')) {
    var $form = $(e.target).parent().parent().parent().find('.comment-form');
    var $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')) {
    var $form = $(e.target).parent().parent().parent().find('.comment-form');
    $form.submit();
  } else if ($(e.target).is('.comment-delete-link')) {
    var chk = confirm('Are you sure you want to delete it?');
    if (chk === false) {
      return;
    }
    var $commentNo = $(e.target).attr('title');
    $('#deleteCommentForm input[name*=commentNo]').val($commentNo);
    $('#deleteCommentForm').submit();
  }
});  

Prev Article link and Next Article link (jQuery)

Next Article link and Prev Article link

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();
  var articleNo = this.title;
  $('#viewForm input[name*=articleNo]').val(articleNo);
  $('#viewForm').submit();
});

Modify/Del/Next Article/Prev Article/List/New Article Button (jQuery)

Modify/Del/Next Article/Prev Article/List/New Article Button

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() {
  var chk = confirm('Are you sure you want to delete it?');
  if (chk === true) {
    $('#delForm').submit();
  }
});
//Next Article Button
$('.next-article').click(function() {
  var articleNo = this.title;
  $('#viewForm input[name*articleNo]').val(articleNo);
  $('#viewForm').submit();
});
//Prev Article Button
$('.prev-article').click(function() {
  var 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)

Title link, Page move links, New Article Button

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();
  var articleNo = this.title;
  $('#viewForm input[name*articleNo]').val(articleNo);
  $('#viewForm').submit();
});
//Paging
$('#paging a').click(function(e) {
  e.preventDefault();
  var 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.