authorId<input>태그에 데이터를 넣기 위해 '작가'를 선택할 수 있도록 '팝업 창'을 띄우고, 원하는 '작가'를 선택을 하게 되면 팝업창은 닫히고 <input>태그에 해당 작가의 id값이 입력되도록 하는 것이 목표입니다.
기존의 작가 입력(authorId) <input>태그 옆에 버튼을 추가할 것입니다. 해당 버튼을 누르게 되면 DB에 등록되어 있는 작가를 선택할 수 있는 팝업창이 뜨도록 구현할 것입니다.
먼저 기존의 작가 <input>태그를 아래의 코드로 수정 및 추가합니다.
첫번째 <input>태그의 경우 사용자에게 보일 부분입니다. 작가의 이름이 출력되도록 할 것입니다. 두번째 <input>태그는 '상품 등록'에 필요로 한 authorId데이터를 저장합니다. 해당 태그는 보이지 않도록 type속성 값을 'hidden'을 부여하였습니다. <button>은 작가 선택을 할 팝업창을 띄우기 위해 추가하였습니다.
<input id="authorName_input" readonly="readonly">
<input id="authorId_input" name="authorId" type="hidden">
<button class="authorId_btn">작가 선택</button>
추가한 태그들의 css설정을 추가하였습니다. goodsEnroll.css에 아래의 코드를 추가합니다.
.authorId_btn { /* 작가 선택 css 설정 */
margin-left: 20px;
width: 14%;
height: 38px;
font-weight: 600;
background-color: #dfe8f5;
font-size: 15px;
cursor:pointer;
}
#authorName_input {
width: 80%;
text-align: center;
}
팝업창은 아래의 코드를 통해 작동합니다.
첫 번째 파라미터는 팝업창의 url주소입니다. 두 번째 파라미터는 팝업창의 이름입니다. 마지막 파라미터는 팝 업창에 대한 설정입니다.
어떠한 설정을 할 수 있는지는 아래의 MDN홈페이지에 들어가면 볼 수 있습니다.
팝업창MDN
var window = window.open(url, windowName, [windowFeatures]);
먼저 <script>태그 아래에 버튼이 클릭되었을 때 동작하는 메서드 추가와 해당 구현부에 버튼의 동작을 멈추는 코드를 추가해주고 팝업창 동작을 실행하는 코드를 추가합니다.(해당 버튼이 <form>태그 내부에 추가되어있기 때문에 기능을 막지 않으면 <form>이 전송됩니다.)
/* 작가 선택 버튼 */
$('.authorId_btn').on("click",function(e){
e.preventDefault();
let popUrl = "/admin/authorPop";
let popOption = "width = 650px, height=550px, top=300px, left=300px, scrollbars=yes";
window.open(popUrl,"작가 찾기",popOption);
});
위의 코드 작성을 마치고 '작가 선택'버튼을 클릭하면 에러 창이 뜹니다. 아직 url매핑 메서드와 팝업창 jsp를 추가해주지 않았기 때문입니다. 그렇기 때문에 AdminController.java에 아래의 url매핑 메서드를 추가해줍니다.
/* 작가 검색 팝업창 */
@GetMapping("/authorPop")
public void authorPopGET() throws Exception {
logger.info("authorPopGET");
}
views/admin폴더 경로에 authorPop.jsp파일을 추가해줍니다. 그리고 authorPop.jsp파일에 해당 페이지가 팝업 페이지임을 표시하도록 문구를 추가하였습니다.
상품 관리 페이지에서 하였던 작가 리스트를 출력하고 검색 기능을 팝업창에서 구현할 것입니다. 기존의 authorManage.jsp에서 구현한 것을 그대로 가져올 것입니다.
"authorPop" url매핑 메서드에 작가 리스트 구현에 필요로 한 Criteria, Model객체를 파라미터로 추가합니다.
/* 작가 검색 팝업창 */
@GetMapping("/authorPop")
public void authorPopGET(Criteria cri, Model model) throws Exception {
logger.info("authorPopGET");
cri.setAmount(5);
/* 게시물 출력 데이터 */
List list = authorService.authorGetList(cri);
if(!list.isEmpty()) {
model.addAttribute("list", list);
} else {
model.addAttribute("listCheck", "empty");
}
/* 페이지 이동 인터페이스 데이터 */
model.addAttribute("pageMaker", new PageDTO(cri, authorService.authorGetTotal(cri)));
}
JSTL을 사용하기 위해서 라이브러리 태그를 파일 상단에 추가하였습니다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
서버로부터 전달받은 "listCheck"와 "pageMaker"데이터를 가지고 '작가 목록'과 '페이지 인터페이스'를 출력하는 코드를 추가합니다. "authorManage.jsp"에 작성한 코드를 복사 붙여 넣기 후 필요양식에 맞게 수정을 하였습니다.
<link rel="stylesheet" href="../resources/css/admin/authorPop.css">
<script
src="https://code.jquery.com/jquery-3.4.1.js"
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
crossorigin="anonymous"></script>
<div class="subject_name_warp">
<span>작가 선택</span>
</div>
<div class="content_wrap">
<!-- 게시물 표 영역 -->
<div class="author_table_wrap">
<!-- 게시물 O -->
<c:if test="${listCheck != 'empty'}">
<div class="table_exist">
<table class="author_table">
<thead>
<tr>
<td class="th_column_1">작가 번호</td>
<td class="th_column_2">작가 이름</td>
<td class="th_column_3">작가 국가</td>
</tr>
</thead>
<c:forEach items="${list}" var="list">
<tr>
<td><c:out value="${list.authorId}"></c:out> </td>
<td><c:out value="${list.authorName}"></c:out></td>
<td><c:out value="${list.nationName}"></c:out> </td>
</tr>
</c:forEach>
</table>
</div>
</c:if>
<!-- 게시물 x -->
<c:if test="${listCheck == 'empty'}">
<div class="table_empty">
등록된 작가가 없습니다.
</div>
</c:if>
<!-- 검색 영역 -->
<div class="search_wrap">
<form id="searchForm" action="/admin/authorPop" method="get">
<div class="search_input">
<input type="text" name="keyword" value='<c:out value="${pageMaker.cri.keyword}"></c:out>'>
<input type="hidden" name="pageNum" value='<c:out value="${pageMaker.cri.pageNum }"></c:out>'>
<input type="hidden" name="amount" value='${pageMaker.cri.amount}'>
<button class='btn search_btn'>검 색</button>
</div>
</form>
</div>
<!-- 페이지 이동 인터페이스 영역 -->
<div class="pageMaker_wrap" >
<ul class="pageMaker">
<!-- 이전 버튼 -->
<c:if test="${pageMaker.prev}">
<li class="pageMaker_btn prev">
<a href="${pageMaker.pageStart - 1}">이전</a>
</li>
</c:if>
<!-- 페이지 번호 -->
<c:forEach begin="${pageMaker.pageStart}" end="${pageMaker.pageEnd}" var="num">
<li class="pageMaker_btn ${pageMaker.cri.pageNum == num ? "active":""}">
<a href="${num}">${num}</a>
</li>
</c:forEach>
<!-- 다음 버튼 -->
<c:if test="${pageMaker.next}">
<li class="pageMaker_btn next">
<a href="${pageMaker.pageEnd + 1 }">다음</a>
</li>
</c:if>
</ul>
</div>
<form id="moveForm" action="/admin/authorPop" method="get">
<input type="hidden" name="pageNum" value="${pageMaker.cri.pageNum}">
<input type="hidden" name="amount" value="${pageMaker.cri.amount}">
<input type="hidden" name="keyword" value="${pageMaker.cri.keyword}">
</form>
</div>
</div>
<script>
let searchForm = $('#searchForm');
let moveForm = $('#moveForm');
/* 작거 검색 버튼 동작 */
$("#searchForm button").on("click", function(e){
e.preventDefault();
/* 검색 키워드 유효성 검사 */
if(!searchForm.find("input[name='keyword']").val()){
alert("키워드를 입력하십시오");
return false;
}
searchForm.find("input[name='pageNum']").val("1");
searchForm.submit();
});
/* 페이지 이동 버튼 */
$(".pageMaker_btn a").on("click", function(e){
e.preventDefault();
console.log($(this).attr("href"));
moveForm.find("input[name='pageNum']").val($(this).attr("href"));
moveForm.submit();
});
</script>
resources/css/admin 경로에 "authorPop.css"파일을 추가해준 뒤 아래의 코드를 추가해주었습니다.
@charset "UTF-8";
/* 전체 wrap */
.wrapper{
width:100%;
height:535px;
}
.subject_name_warp{
font-size: 33px;
font-weight: bolder;
padding-left: 15px;
background-color: #6AAFE6;
height: 13%;
line-height: 70px;
color: white;
}
.content_wrap{
height:87%;
}
/* 작가 목록 영역 */
.author_table_wrap{
padding: 20px 35px
}
.table_exist{
height:251px;
}
.author_table{
width: 100%;
border: 1px solid #d3d8e1;
text-align: center;
border-collapse: collapse;
}
.author_table td{
padding: 10px 5px;
border : 1px solid #e9ebf0;
}
.author_table thead{
background-color: #f8f9fd;
font-weight: 600;
}
.author_table a{
color:#1088ed;
font-weight: 500;
}
.th_column_1{
width:120px;
}
.th_column_3{
width:110px;
}
.table_empty{
text-align: center;
margin: 101px 0 130px 0;
font-size: 25px;
}
/* 검색 영역 */
.search_wrap{
margin-top:25px;
}
.search_input{
position: relative;
text-align:center;
}
.search_input input[name='keyword']{
padding: 4px 10px;
font-size: 15px;
height: 20px;
line-height: 20px;
}
.search_btn{
height: 32px;
width: 80px;
font-weight: 600;
font-size: 18px;
line-height: 20px;
position: absolute;
margin-left: 15px;
background-color: #c3daf7;
}
/* 페이지 버튼 인터페이스 */
.pageMaker_wrap{
margin-top: 20px;
margin-bottom: 40px;
}
.pageMaker{
list-style: none;
display: inline-block;
}
.pageMaker_btn {
text-align: center;
float: left;
width: 30px;
height: 30px;
line-height: 30px;
margin-left: 8px;
font-size: 15px;
}
.active{
border : 2px solid black;
font-weight:400;
}
.next, .prev {
border: 1px solid #ccc;
padding: 0 10px;
}
.next a, .prev a {
color: #ccc;
}
팝업창의 작가 이름을 클릭하였을 때 팝업창이 닫히면서 부모 창의 작가 <input>태그에 데이터 입력되도록 구현할 것입니다.
MDN페이지
Javascript코드를 통해 제어할 것인데 위의 MDN페이지에 있는 부모 창의 요소에 접근하는 방법을 참고하면 됩니다. 링크의 페이지에서 부모 창을 접근하기 위한 키워드는 "openr"입니다.
작가의 이름을 아래의 <a>태그로 감싸줍니다.
<a class="move" href='<c:out value="${list.authorId}"/>' data-name='<c:out value="${list.authorName}"/>'>
<c:out value="${list.authorName}"></c:out>
</a>
<script>태그에 추가한 <a>태그를 눌렀을 때 동작시킬 코드를 추가합니다.
/* 작가 선택 및 팝업창 닫기 */
$(".move").on("click", function(e){
e.preventDefault();
let authorId = $(this).attr("href");
let authorName= $(this).data("name");
$(opener.document).find("#authorId_input").val(authorId);
$(opener.document).find("#authorName_input").val(authorName);
window.close();
});