Kim VamPa

[Spring][쇼핑몰 프로젝트][18] 상품 등록 - 작가 선택(팝업창) 구현 - 2 본문

스프링 프레임워크/쇼핑몰 프로젝트

[Spring][쇼핑몰 프로젝트][18] 상품 등록 - 작가 선택(팝업창) 구현 - 2

Kim VamPa 2021. 3. 29. 10:00
728x90
반응형
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188

목표

팝업창 선택 데이터 부모 창 전달

 저번 포스팅에선 팝업창을 띄우는 것을 구현하였습니다. 이번 포스팅에선 팝업창에서 작가를 검색하고 선택할 수 있도록 인터페이스를 구현하고, 최종적으로 선택한 데이터가 부모 창(goodsEnroll.jsp)에 전달하는 것을 목표로 합니다.

 

 

순서

1. 작가 목록 구현(팝업창)

2. 부모 창 데이터 전달

3. 테스트

 

 

 

1. 작가 목록 구현(팝업창)

1.1 Controller 작업

 

 상품 관리 페이지에서 하였던 작가 리스트를 출력하고 검색 기능을 팝업창에서 구현할 것입니다. 이번 작업은 크게 어려운 작업은 아닙니다. 왜냐하면 기존의 authorManage.jsp에서 구현한 것을 거의 그대로 가져올 것이기 때문입니다. 

 

 "authorPop" url 매핑 메서드에 작가 리스트 구현에 필요로 한 Criteria, Model 객체를 파라미터로 추가합니다.

 

	/* 작가 검색 팝업창 */
	@GetMapping("/authorPop")
	public void authorPopGET(Criteria cri, Model model) throws Exception{
		
		logger.info("authorPopGET.......");
	
	}	

 

그림 1-1

 

 "authorManage" url 매핑 메서드에 있는 구현부의 코드를 복사하여 구현 부에 붙여 넣어줍니다. 

 

		/* 게시물 출력 데이터 */
		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)));	

 

그림 1-2

 

 그런데 저상태로 "팝업창"에 작가 목록 리스트를 전송하면 10개씩 전송이 됩니다. 팝업창 크기가 작기 때문에 좀 더 작은 단위로 작가 데이터를 전송할 것입니다.

 

 따라서 Criteria에 기본적으로 초기화되어 있는 amount 변수 값 10을 5로 변경해주는 코드를 추가해줍니다.

 

cri.setAmount(5);

 

그림 1-3

 

1.2 View 작업

 

 JSTL을 사용하기 위해서 라이브러리 태그를 파일 상단에 추가하였습니다.

 

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>  

 

그림 1-7

 

 서버로부터 전달받은 "listCheck"와 "pageMaker" 데이터를 가지고 '작가 목록'과 '페이지 인터페이스'를 출력하는 코드를 추가합니다. "authorManage.jsp"에 작성한 코드를 복사 붙여 넣기 후 필요양식에 맞게 수정을 하였습니다.

 

※ "[15] 작가 목록 기능 구현" 포스팅과 동일한 과정의 코드이기 때문에 자세한 설명은 생략하겠습니다.

 

		<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>

 

그림 1-4

 

 css 설정을 추가해주기 위해 아래의 <link> 태그를 추가해줍니다.

 

<link rel="stylesheet" href="../resources/css/admin/authorPop.css">

 

그림 1-5

 

 resources/css/admin 경로에 "authorPop.css" 파일을 추가해준 뒤 아래의 코드를 추가해주었습니다.

 

/* 전체 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;
}

 

그림 1-6

 

 팝업창을 들어가면 아래의 그림과 같이 출력됩니다.

 

그림 1-9

 

 페이지 인터페이스가 동작하도록 Javascript코드를 추가하지 않았기 때문에 하단의 페이지 버튼을 클릭 시 에러 창이 뜹니다.

 

 Jquery을 사용하기 위해 라이브러리 태그 코드를 추가해줍니다.

 

<script
  src="https://code.jquery.com/jquery-3.4.1.js"
  integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
  crossorigin="anonymous"></script>

 

 

 

 페이지 버튼이 동작하도록 'authorPop.jsp'파일 하단에 <script> 태그를 추가해준 뒤 아래의 코드를 추가해줍니다. 

 

	<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>

 

그림 1-11

 

 위 코드를 작성 후 페이지 이동 버튼을 클릭 시 정상적으로 동작이 됩니다.

 

 

2. 부모 창 데이터 전달

 팝업창의 작가 이름을 클릭하였을 때 팝업창이 닫히면서 부모 창의 작가 <input> 태그에 데이터 입력되도록 구현할 것입니다.

 

 Javascript 코드를 통해 제어할 것인데 아래의 MDN 페이지에 있는 부모 창의 요소에 접근하는 방법을 참고하였습니다. 

 

developer.mozilla.org/ko/docs/Web/API/Window/opener

 

위 링크의 페이지에 따르면 부모 창을 접근하기 위한 키워드는 "opener"입니다. 이를 활용해서 작업을 진행하겠습니다.

 

 작가 이름을 아래의 <a> 태그로 감싸줍니다.

 

<a class="move" href='<c:out value="${list.authorId}"/>' data-name='<c:out value="${list.authorName}"/>'>
</a>

 

그림 2-1

 

- 태그 속성에 data-name 속성을 추가시켜서 <a> 태그에 '작가 이름' 데이터를 저장시켰습니다. 해당 데이터를 Javascript에서 꺼내 쓰기 위해서는 '선택자. data("name")' 코드를 통해 사용할 수 있습니다.

 

※ 이는 'data 속성'이라는 기능입니다. "data 속성" 키워드를 통해 검색하셔서 찾아보시거나 아래의 홈페이지를 참고하시면 됩니다.

 

developer.mozilla.org/ko/docs/Learn/HTML/Howto/Use_data_attributes

 

 

 

 <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();

		});	

 

그림 2-2

 

 작성한 메서드 구현부를 해석하면 먼저 <a> 태그의 동작을 멈춘 뒤, 'authorId'와 'authorName' 변수를 사용자가 클릭한 <a>태그 속성에 저장된 authorId, authorName 데이터로 초기화시킵니다. $(opener.document)'를 통해 부모 요소 접근하여 각 <input> 태그에 'authorId', 'authorName' 변수의 값을 삽입합니다. 마지막으로 widnow.close()를 통해 팝업창을 닫습니다.

 

 

3. 테스트

 팝업창을 통해 선택한 작가 데이터가 부모 창에 입력이 되는지 테스트합니다.

 

그림 3-1

 

그림 3-2

 

그림 3-3

 

그림 3-4

 

 

REFERENCE

 

DATE

  • 2020.03.29
728x90
반응형
Comments