캘린더에서 각각의 날짜 영역을 선택할 때마다 해당 값을 읽어와 input태그에 추가시키고한번 더 클릭시 선택을 해제하며 해당 값을 제거하고 싶었다.
사실 datepicker를 가져와 쓰면 간단하게 해결될 문제였을텐데, 어쩌다보니 반 이상을 직접 구현하게 되어 별개의 일자를 정렬시키고 처리 시키는 일이 필요했다.
문제는 어떻게 정렬시킬 것인가? 그리고 어떤 형태로 DB에 넣을 것인가? 어디서 처리할것인가?(컨트롤러? 뷰단?)
1. 컨트롤러에서 처리split()으로 잘라 배열에 넣고, List로 변경하여 sort()를 통해 정렬그러나 문제는 DB에 어떻게 넣을건지였다.처음에는 요청별로 휴가 시작일과 종료일을 넣으려다가, 7/8 7/9 7/20 이런식으로 연속되다가 연속되지 않은 일자들이 존재할 때어떻게 연속되는 날짜를 구분해서 시작일과 종료일을 만들지? 만든다 하더라도 요청을 또 쪼개서 DB에 넣는 게 맞는건가?DatePicker를 지금이라도 사용해야 하나 고민했다.
그러다가 생각해보니, 넣을 때도 꺼내쓸 때도 그냥 하나의 휴가기간 컬럼에다 [7/8 7/9 7/20]와 같은 문자열 자체를 넣는 게 가장 간단할 것 같았다.
처음엔 이런 코드였으나... 아주 복잡하고 컨트롤러는 작성하다 말았다.
function readDate(target){
let cdate = (CDate.getMonth()+1)+'/'+target.innerText+' ';
let input = document.getElementById('vac-period');
if(cnt==document.getElementById('rest').value && !input.value.includes(cdate)){
alert("잔여연차를 초과하셨습니다.");
} else if(cnt<document.getElementById('rest').value){
target.style.background='var(--imp-color)';
target.style.color = 'white';
if(input.value.includes(cdate)){
target.style.background = 'transparent';
target.style.color = 'var(--base-color)';
input.value=document.getElementById('vac-period').value.replace(cdate,'');
input.value=document.getElementById('vac-period').value.replace("("+cnt+")",'');
cnt--;
let sCnt1 = "(" + cnt + ")";
input.value+= sCnt1;
}
else{
input.value=document.getElementById('vac-period').value.replace("("+cnt+")",'');
cnt++;
let sCnt2 = "(" + cnt + ")";
input.value += cdate;
input.value += sCnt2;
}
} else {
target.style.background = 'transparent';
target.style.color = 'var(--base-color)';
input.value=document.getElementById('vac-period').value.replace(cdate,'');
input.value=document.getElementById('vac-period').value.replace("("+cnt+")",'');
cnt--;
let sCnt1 = "(" + cnt + ")";
input.value+= sCnt1;
}
}
String[] p = period.split(" ");
ArrayList<String> list = new ArrayList<>(Arrays.asList(p));
// 오름차순으로 정렬 [(n), 1, 2, 3, ...]
Collections.sort(list);
String[] m = new String[(p.length-1)];
String[] d = new String[(p.length-1)];
/*월, 일 쪼개서 배열에 저장*/
for(int i=1; i<p.length; i++) {
m[i] = p[i].split("/")[0];
d[i] = p[i].split("/")[1];
}
/*비교하여 기간별 요청 만들기*/
//임시 요청 배열
String[] req;
코드를 어떻게 바꿀까 생각하는데, 역시나 처음부터 뷰단에서 스크립트를 통해 값을 정렬해 보여주고 받아오는 것이 나을 것 같았다.
정렬을 하려면 배열을 써야겠지 → sort()
배열에서 특정 값을 제거하려면? → splice()
둘을 써서 쓰니 코드가 훨씬 단순해졌다.
그런데 또 문제가, 자바스크립트에서 sort() 기본함수를 통해 정렬할 때 아스키 코드를 이용하기 때문에
7/24보다도 7/4가 후순위를 가진다는 것이었다.
찾아보니 또 이건, 일종의 정렬함수를 custom하기 위해 sort()안에 람다식을 매개변수로 주면 해결가능한 것 같다.
그래서 일단은 7/24.split('/')으로 일자를 분리해내 (a,b => a-b)와 같은 람다식으로 리턴값이 음수인지 양수인지에 정렬함수를 재정의(?)하게 됐다. 사실 람다식은 대충 공부해서 정확히 이해가 안되는데, 나중에 찾아봐야겠다.
결국엔 내가 원하는 정렬값을 얻을 수 있었다.
아래는 최종 자바스크립트 코드
function readDate(target){
let cdate = (CDate.getMonth()+1)+'/'+target.innerText;
let input = document.getElementById('vac-period');
//잔여연차를 초과하여 추가 선택하려할 때
if(cnt==document.getElementById('rest').value && !input.value.includes(cdate)){
alert("잔여연차를 초과하셨습니다.");
//잔여연차가 있을 때
} else if(cnt<document.getElementById('rest').value){
//선택된 날짜 한번 더 클릭하여 해제
if(input.value.includes(cdate)){
target.style.background = 'transparent';
target.style.color = 'var(--base-color)';
input.value='';
pr.splice(pr.indexOf(cdate),1);
for(let i=0; i<pr.length; i++){ input.value += (pr[i] +' ');}
cnt--;
let sCnt1 = "(" + cnt + ")";
input.value+= sCnt1;
//클릭하여 선택
} else {
target.style.background='var(--imp-color)';
target.style.color = 'white';
input.value='';
cnt++;
let sCnt2 = "(" + cnt + ")";
pr.push(cdate);
pr.sort((a, b) => a.split('/')[1] - b.split('/')[1]);
for(let i=0; i<pr.length; i++){ input.value += (pr[i]+' '); }
input.value += sCnt2;
}
//잔여연차를 초과한 상황에서 선택한 날짜를 해제할 때
} else {
target.style.background = 'transparent';
target.style.color = 'var(--base-color)';
input.value='';
pr.splice(pr.indexOf(cdate),1);
for(let i=0; i<pr.length; i++){ input.value += (pr[i]+' '); }
cnt--;
let sCnt1 = "(" + cnt + ")";
input.value+= sCnt1;
}
}
그런데 또 문제 생김
연도, 달까지 정렬할 생각을 미처 못했다.
결국엔 sort() 기본함수로 회귀했고,
새로 알게된 사실은 자바스크립트 Date객체엔 format() 기본함수가 없다는 것
그래서 다들 원하는 모양을 만들 수 있는 메소드를 정의해 쓰는 듯했다.
내가 원한건 단순 yy-MM-dd였는데... 문자열로 직접 만들고 싶지 않아 아무리 format() 함수에 대해 찾아 헤매도, 그리고 시도해보아도 실패였다.
여튼 수동으로 yy-MM-dd 형태를 주고 나니, 달리 sort() 함수를 재정의하지 않아도 알아서 정렬할 수 있게 되어 이게 난듯하다.
let CDate = new Date();
let today = new Date();
buildCalendar();
function buildCalendar() {
let prevLast = new Date(CDate.getFullYear(), CDate.getMonth(), 0);
let thisFirst = new Date(CDate.getFullYear(), CDate.getMonth(), 1);
let thisLast = new Date(CDate.getFullYear(), CDate.getMonth() + 1, 0);
document.querySelector(".yearTitle").innerHTML = CDate.getFullYear() + '년';
//상단에 년도 출력
document.querySelector(".monthTitle").innerHTML = CDate.getMonth() + 1 + '월';
//상단에 월 출력
let dates = [];
let prevDates = [];
let nextDates = [];
//현재 월 달력에 쓰일 날짜를 모을 배열
if (thisFirst.getDay() != 0) {//만약 이번 월의 첫째날이 일요일이 아니라면
for (let i = 0; i < thisFirst.getDay(); i++) {//일요일부터 이번 월의 요일까지 날짜를 구하기 위한 for문
prevDates.unshift(prevLast.getDate() - i);//이전 월의 마지막 날짜부터 1씩 빼가며 unshift(배열 앞에 값을 넣습니다.)
}
}
for (let i = 1; i <= thisLast.getDate(); i++) {//이번 월 날짜 구하기
dates.push(i);
}
for (let i = 1; i <= 13 - thisLast.getDay(); i++) {//다음 월 날짜 구하기 13에서 빼는 이유는, 2월달력의 경우 최대 3월 13일까지 표시될 수 있음
nextDates.push(i);
}
//선택한 날짜 달력에 체크하기 - 날짜 쪼개서 배열로 보관
var periods = document.getElementById('vac-period').value.split(' / ');
var check = [];
for(var i=0; i<periods.length-1; i++){
var period = periods[i].split('-');
var y = period[0]
var m = period[1];
var d = period[2];
if(m == CDate.getMonth()+1){
check.push(d);
}
}
let htmlDates = '';//날짜 정보를 html형식으로 저장할 변수
for (let i = 0; i < prevDates.length; i++) {//42일을 출력할 for문
htmlDates += `<div class="date choice-date except">${prevDates[i]}</div>`
}
for (let i = 0; i < dates.length; i++) {//42일을 출력할 for문
/*이번달 오늘 이전이거나 과거일때(이번 해 이전달들 혹은 지난해들)*/
if(dates[i]<today.getDate() && CDate.getMonth() == today.getMonth()|| CDate.getMonth() < today.getMonth() && CDate.getFullYear() <=today.getFullYear() ){
htmlDates += `<div class="date choice-date except">${dates[i]}</div>`
}
else{//오늘이라면
if (today.getDate() == dates[i] && today.getMonth() == CDate.getMonth() && today.getFullYear() == CDate.getFullYear()) { //만약 년도, 월, 일이 똑같은 dates[i]값이 나오면 class에 today를 추가하기 위함.
//이를 이용해서 today표시
htmlDates += `<div class="date choice-date"><span class="today">${dates[i]}</span></div>`;
//오늘 이후라면
} else {
let y = false;
for(let j=0; j<check.length; j++){
//선택된 날짜일때
if(dates[i]==check[j]){
htmlDates += `<div class="date choice-date" onclick="readDate(this)" style="background:var(--imp-color); color:white;">${dates[i]}</div>`
y = true;
}
}
if(y==false)
htmlDates += `<div class="date choice-date" onclick="readDate(this)">${dates[i]}</div>`
}
}
}
for (let i = 0; i < nextDates.length; i++) {//42일을 출력할 for문
htmlDates += `<div class="date choice-date except">${nextDates[i]}</div>`
}
document.querySelector(".dates").innerHTML = htmlDates;//htmlDates를 index.html의 .dates안에 넣는 작업
} //<i class="fas fa-exclamation-circle"></i>
function prevCal() { CDate.setMonth(CDate.getMonth() - 1); buildCalendar(); }
function nextCal() { CDate.setMonth(CDate.getMonth() + 1); buildCalendar(); }
var cnt = 0;
var pr = [];
function readDate(target){
let vDate = new Date();
let d = target.innerText;
if(d.length==1) d = '0'+d;
let m = (CDate.getMonth()+1).toString();
if(m.length==1) m = '0'+m;
let y = CDate.getFullYear().toString();
y = y.substr(2,2);
let cdate = y +'-'+ m +'-'+ d;
console.log("cdate:"+cdate);
console.log("cnt : " +cnt);
let input = document.getElementById('vac-period');
//잔여연차를 초과하여 추가 선택하려할 때
if(cnt==document.getElementById('rest').value && !input.value.includes(cdate)){
alert("잔여연차를 초과하셨습니다.");
//잔여연차가 있을 때
} else if(cnt<document.getElementById('rest').value){
//선택된 날짜 한번 더 클릭하여 해제
if(input.value.includes(cdate)){
target.style.background = 'transparent';
target.style.color = 'var(--base-color)';
pr.splice(pr.indexOf(cdate),1);
for(let i=0; i<pr.length; i++){
if(i==0) input.value = pr[i];
else input.value += (' / ' + pr[i]);
}
cnt--;
let sCnt1 = " (" + cnt + ")";
input.value+= sCnt1;
//클릭하여 선택
} else {
target.style.background='var(--imp-color)';
target.style.color = 'white';
cnt++;
let sCnt2 = " (" + cnt + ")";
pr.push(cdate);
pr.sort();
for(let i=0; i<pr.length; i++){
if(i==0) input.value = pr[i];
else{
input.value += (' / ' + pr[i]);
}
}
input.value += sCnt2;
}
//잔여연차를 초과한 상황에서 선택한 날짜를 해제할 때
} else {
target.style.background = 'transparent';
target.style.color = 'var(--base-color)';
input.value='';
pr.splice(pr.indexOf(cdate),1);
for(let i=0; i<pr.length; i++){
if(i==0) {input.value = pr[i];}
else input.value += (' / ' + pr[i]);
}
cnt--;
let sCnt1 = " (" + cnt + ")";
input.value+= sCnt1;
}
}
function checkEvi() {
var imgname = document.getElementById('vac-prove').value;
if (imgname == "") {
alert("이미지를 첨부해주세요.");
return false;
}
return true;
}
참고한 글
sort()
https://codingbroker.tistory.com/41
[javascript] 배열 정렬하는 방법(숫자 오름차순/내림차순, 임의정렬) - sort
자바스크립트에서 배열을 정렬하는 방법에 대해 살펴보겠습니다. sort 메소드를 사용합니다. array.sort( 비교함수 ) 비교함수를 기준으로 배열 내의 요소를 정렬합니다. 원본 배열입니다. const arr =
codingbroker.tistory.com
splice
http://www.gisdeveloper.co.kr/?p=2113
[JavaScript] array의 splice 함수 정리 – GIS Developer
자바스크립트의 배열(Array) 객체에서 제공되는 함수인 splice를 이용하면 원하는 위치에 요소를 추가하거나 삭제할 수 있습니다. 먼저 splice 함수를 사용해 원하는 위치에 요소를 추가하는 것을 정
www.gisdeveloper.co.kr
'FRONT-END > JavaScript & JQuery' 카테고리의 다른 글
뉴렉처 자바스크립트 (0) | 2021.08.02 |
---|---|
캘린더 구현(자바스크립트) (0) | 2021.07.02 |