[JavaScript] 변수 흐름과의 싸움🤨#3
아래 글에서 이어짐!
이번엔 날짜를 줄였을 때 발생하는 문제 2개를 제대로 동작하도록 바꿔보자!
문제 상황 - 1
초기 화면에서 여행 종료일을 8월 30일에서 29일으로 줄였을 때의 정상적인 동작은
1. 해운대블루라인파크라는 글자 앞에 인덱스가 3이 되어야하고, 해리단길은 4가 되어야한다.
2. 아래 span placeNumber 클래스 태그를 보면 id 값이 동백섬은 1-2로 되어있고 해운대블루라인파크는 2-1로 되어있는데 원래는 [일차]-[몇번째장소]기 때문에 해운대블루라인파크는 1-3이 되어야한다.
아래 캡쳐를 보면 정상적으로 동작되지 않고 있다.
해결 방법 - 1
작성된 코드를 살펴보자. 아래 코드는 날짜 변경 시 일정을 조정하는 함수인 updateTripDates() 내에 포함된 코드이다.
날짜 범위를 줄였을 때 if문이 실행된다.
// 만약 새로운 날짜 범위가 기존 날짜보다 짧다면, 남는 날짜의 장소들을 마지막 날로 합침
if (newDateIndex < existingTripData.length) {
// 새로운 날짜 범위에 포함되지 않는 남은 날짜들(existingTripData[newDateIndex] 이후)에 있는 모든 장소들을 모아서 lastTripLocations에 저장
const lastTripLocations = existingTripData
.slice(newDateIndex) // 기존 데이터에서 새로운 날짜 범위 이후의 데이터를 잘라냄
.flatMap(data => data.tripLocations); // 잘라낸 데이터에서 각 날짜의 장소들(tripLocations)을 추출하여 하나의 배열로 만듦
// 새로운 날짜 범위에서 마지막 날에 해당하는 trip-locations 요소를 찾음
const lastDayElement = newTripDatesContainer.querySelector('.trip-date:last-child .trip-locations');
// 남은 날짜들의 장소들(lastTripLocations)을 하나씩 마지막 날에 추가
lastTripLocations.forEach((loc, index) => {
lastDayElement.insertAdjacentHTML(
'beforeend', // lastDayElement의 마지막 자식 요소로 새로운 장소 요소를 추가
createTripLocationHtml(loc, newDateIndex + 1, index + 1)); // 남은 날짜의 장소(loc)를 HTML로 생성하여 추가
});
}
// 날짜 카운트 업데이트 (Day 숫자 업데이트)
updateDayCount();
콘솔에 existingTripData, tripDateData, newDateIndex 를 찍어보자.
existingTripData은 날짜 변경 전 기존 날짜, 장소 데이터가 저장되어있다.
let newDateIndex = 0;
// 시작 날짜부터 종료 날짜까지 반복하며 날짜를 생성
for (let date = new Date(startDate); date <= endDate; date.setDate(date.getDate() + 1)) {
// 현재 날짜에 해당하는 기존 여행 데이터가 있으면 가져옴, 없으면 빈 객체 사용
const tripDateData = existingTripData[newDateIndex] || {};
const dayNum = newDateIndex + 1;
// 기존 addTripDate 함수 호출하여 새로운 날짜를 추가
addTripDate({
tripDate: date.toISOString().split('T')[0],
tripLocations: tripDateData.tripLocations || []
});
newDateIndex++;
}
newDateIndex은 0부터 시작해서 기존 날짜 범위에 있는 데이터들을 추가해주는 addTripDate()을 호출 한 뒤 +1 된다.
tripDateData은 const tripDateData = existingTripData[newDateIndex] || {}; 이렇게 날짜 변경 후 현재 날짜에 해당하는 기존 데이터가 있으면 가져오고, 없으면 빈 객체로 만들어진다.
그럼 종료일을 8월 30일에서 29일로 줄였기 때문에 8월 30일 데이터들인 해운대블루라인파크와 해리단길을 8월 29일에 추가해야하는데, 그 때 if (newDateIndex < existingTripData.length)이 true기 때문에 if문 내부를 실행하게된다.
아까 봤던 if문 내부와 문서 구조를 다시 살펴보자.
// 만약 새로운 날짜 범위가 기존 날짜보다 짧다면, 남는 날짜의 장소들을 마지막 날로 합침
if (newDateIndex < existingTripData.length) {
// 새로운 날짜 범위에 포함되지 않는 남은 날짜들(existingTripData[newDateIndex] 이후)에 있는 모든 장소들을 모아서 lastTripLocations에 저장
const lastTripLocations = existingTripData
.slice(newDateIndex) // 기존 데이터에서 새로운 날짜 범위 이후의 데이터를 잘라냄
.flatMap(data => data.tripLocations); // 잘라낸 데이터에서 각 날짜의 장소들(tripLocations)을 추출하여 하나의 배열로 만듦
// 새로운 날짜 범위에서 마지막 날에 해당하는 trip-locations 요소를 찾음
const lastDayElement = newTripDatesContainer.querySelector('.trip-date:last-child .trip-locations');
// 남은 날짜들의 장소들(lastTripLocations)을 하나씩 마지막 날에 추가
lastTripLocations.forEach((loc, index) => {
lastDayElement.insertAdjacentHTML(
'beforeend', // lastDayElement의 마지막 자식 요소로 새로운 장소 요소를 추가
createTripLocationHtml(loc, newDateIndex + 1, index + 1)); // 남은 날짜의 장소(loc)를 HTML로 생성하여 추가
});
}
내부 구조가 이렇게 되어있어서 trip-locations 아래에 있는 trip-location에 해운대해수욕장 같은 장소정보가 들어간다.
지금 id="1-1" 처럼 표현되는 span 태그 내의 id가 잘못들어가고 있는거니, createTripLocationHtml()에 넘겨주는 전달인자가 잘못된 것이 원인이라고 볼 수 있다.
createTripLocationHtml(loc, newDateIndex + 1, index + 1)); 이렇게 넘겨주는 것을
createTripLocationHtml(tripLocationData, dayNum, placeIndex) 이렇게 받는다.
그럼 dayNum이 newDateIndex + 1이 되는 것이고, placeIndex가 index + 1이 되는 것이다.
createTripLocationHtml에서 span 태그 id를 지정하는 방법은 const uniqueId = ${dayNum}-${placeIndex}; 이렇게 정의한다.
즉, 1-3이 되어야할 id가 2-1이 되고 있으니,
newDateIndex는 이미 1일차면 1, 2일차면 2로 알맞게 증가되고 있기 때문에 +1이 아닌 그대로 넘겨주고, placeIndex가 되는 값은 index + 1에 이미 해당 날짜에 존재하는 데이터의 길이를 더해주면 된다.
즉, createTripLocationHtml(loc, newDateIndex, existingTripData.length + index + 1));
이렇게 지정해주면 알맞게 해결된다!
문제 상황 - 2
문제 상황 1에서 선택된 장소들을 저장하는 객체 selectedPlaces에는 selectedPlaces[1]으로 나타나는 1일차 장소 배열에는 해운대해수욕장과 동백섬만 저장되어있고, selectedPlaces[1]에 함께 저장되어있어야할 해운대블루라인파크와 해리단길은 아예 추가되지 않은 것을 볼 수 있다.
지도에 나타나는 마커를 저장하는 markers 객체에도 마찬가지로 해운대블루라인파크와 해리단길은 아예 추가되지 않았다.
해결 방법 - 2
createTripLocationHtml()은 단지 HTML만 생성해주는 함수이고, selectedPlaces와 markers에 데이터를 추가하는 건 addTripDate()에서 이루어진다.
그렇기 때문에 if문에 selectedPlaces와 markers에 데이터 추가하는 부분도 넣어줘야한다.
코드에 데이터 추가하는 부분을 작성해주었다.
// 남은 날짜들의 장소들(lastTripLocations)을 하나씩 마지막 날에 추가
lastTripLocations.forEach((loc, index) => {
lastDayElement.insertAdjacentHTML(
'beforeend', // lastDayElement의 마지막 자식 요소로 새로운 장소 요소를 추가
createTripLocationHtml(loc, newDateIndex, existingTripData.length + index + 1) // 남은 날짜의 장소(loc)를 HTML로 생성하여 추가
// newDateIndex은 장소 uniqueId의 dayNum이 되고, existingTripData.length + index + 1은 장소 순서가 됨(lastTripLocations의 index는 0부터 시작하므로 +1 해줌)
);
// selectedPlaces 객체에 데이터 추가
if (!selectedPlaces[newDateIndex]) {
selectedPlaces[newDateIndex] = [];
}
selectedPlaces[newDateIndex].push({
placeName: loc.placeName,
latitude: loc.latitude,
longitude: loc.longitude
});
// 지도에 마커 추가
const placePosition = new kakao.maps.LatLng(loc.latitude, loc.longitude);
addSelectedMarker(placePosition, existingTripData.length + index + 1, newDateIndex);
// 마커 번호 재정렬
reorderMarkers(markers, newDateIndex);
// 지도 범위 재설정
setBounds(placePosition);
// 지도에 선 표시
drawLinePath(newDateIndex, placePosition);
});
코드 수정 후 확인해보면 제대로 나타난다!
수정 후 로그에 찍힌 걸 보면 selectedPlaces[2]는 없는데 markers[2]는 남아있는 이유는
selectedPlaces은 selectedPlaces = {}; 로 아예 싹 다 비우고 addTripDate() 내부에서 push하고, 또 selectedPlaces[newDateIndex].push로 추가해주는 반면에,
markers는 clearAllMarker()로 markers 초기화하는데 clearAllMarker() 내부에서 markers[dayNum] = []; 이렇게 지정해주기 때문에 markers[2]의 내부만 초기화된다.
근데 뭐 markers[2]가 있어도 상관 없기 때문에 신경쓰지 않았다…!
자바스크립트 코드가 눈에 익숙하지 않아서 파악하는게 좀 힘들었지만 해결하면 바로바로 보여서 나름 재밌었다🫠
나중에 또 헤맬까봐 정리해두기 완료....!🫢