카카오 맵 커스텀 오버레이 여러개 닫기 질문

안녕하세요. 카카오 맵 api를 사용해서 작은 프로젝트를 준비하고 있는 학생입니다. 아직 이 api에서 사용하는 언어를 할 줄 몰라 검색으로 코드를 간신히 짜고 있습니다ㅠㅠ. 커스텀 오버레이를 여러개 만드는 것 까지는 어떻게 성공했습니다. 근데 닫기 버튼을 누르면 마지막으로 여는 마커만 닫히는 에러때문에 고생하고있습니다. 전 질문자분들의 답변을 보니 "document.createElement로 만든 HTMLElement를 content로 넘겨주시는 방식으로 변경하셔야 합니다."라는 답변들을 봤습니다. 근데 아직 변환하는 방법을 잘 모르겠어서 다른 글들을 찾아보면서 2일동안 해봐도 에러만 나네요…ㅠㅠ 그래도 DB연결을 통해 마커는 여러개 생성이 되게 했습니다. 혹시 샘플 코드를 유지한채로 모든 마커들을 각각 닫을 수 있게 바꿀 수 있는 방법을 알 수 있을까요? 아니면 해당 샘플 코드들을 “document.createElement” 형태로 바꿀 수 있는 가이드를 얻을 수 있을까요? 현재 코드는 다음 이미지와 같습니다.



@mrhan1

이 예제로 응용해보실 수 있지 않을까요?

https://apis.map.kakao.com/web/sample/multipleMarkerControl/

안녕하세요~

해당 코드를 유지한채 해결을 하실려면,

for문 바깥에 overlayList = [ ]; 라는 배열을 만들고,
for문 안에서 순환하면서 객체 생성을 할때 overlayList배열에 overlay를 하나씩 overlayList.push()함수를 통해서 삽입합니다.

그리고 content 부분에 onclick=“closeOverlay()” 부분을
onclick=“closeOverlay(‘+i+’)” 와 같이 onclick에 매핑된 함수가 실행될때 특정 인덱스(i)값을 넘기고

closeOverlay함수는 파라미터로 index를 받아, 그 안에서 overlayList[index].setMap(null)을 해주시면 해결이 되실것 같습니다.

다만 현재 위 코드는 잠재적인 문제가 있는데,
marker의 경우에도 마지막 마커만 반응할 것으로 보이고,
현재 위 코드를 정확히 이해하셨는지는 알 수 없으나
var 키워드는 function scope를 가지기 때문에 for문 안에서 marker를 만들어도 그 밖에서 사용할 수가 있고, 항상 marker, overlay변수는 마지막에 생성된 객체를 가지고 있을 수밖에 없습니다.

이렇게 var키워드를 포함한 scope에 대한 이해를 좀더 해보시는게 좋을 것 같고, 현재 IE의 버전 낮은 브라우저를 타겟팅 하는게 아닌, 크롬이나 엣지와 같은 최신 브라우저를 타겟으로 개발하신다면, let, const와 같은 block scope 관련된 키워드를 이용해 보시는게 좋습니다.

그리고 지도 API관련된 부분에서
CustomOverlay에 content를 문자열로 넣으면, 이는 최종적으로 innerHTML이라는 속성을 통해 브라우저에서 파싱이 되는데, 이렇게 하는 경우엔 각 파싱된 DOM태그들을 제어하기가 좀 까다롭습니다.
여러개의 커스텀오버레이들을 관리하려면 별도의 자료구조(위에서는 배열을 사용)를 사용하여 레퍼런스들을 관리해야합니다. 그래서 이전의 다른 분의 답변에서처럼 직접 DOM을 생성하여 작성을 하는게, 추후 코드들의 모듈화에도 좋고, 재사용성도 올라가기에 그렇게 추천을 한게 아닐까 합니다.

Javascript는 접근성이 쉬운언어이나 잘못 이해하면 상당히 난해한 언어이기도 합니다.(왜??? 라는 의문이 종종 뜨는 언어이기도 합니다 ㅎㅎ)
그래서 초반에 기초를 잡을 수 있는 책이나, 문서로 학습을 조금 하시는게 도움이 많이 되고 시행착오의 시간을 줄일 수 있는 방법이 되지 않을까 싶습니다.

1개의 좋아요

감사합니다 덕분에 일어나자마자 DOM형식 공부 후에 DOM을 생성해 만들어봤습니다. 여기까지 진행되는 중에 궁금한 점과 모르는 점이 있어서 답글 남깁니다! 스크립트 내에서 타임리프를 작성하기 위해 /*<![CDATA[*/ /*]]>*/ 이걸로 감싸주고 사진과 같이 작성하면 모두 적용이 되는지 궁금합니다. 그리고 이제 마커를 생성하고 닫는 부분의 코드를 짜야되는데 위 글 같이 작성하면 되는지 아니면 다른 방법으로 새롭게 작성해야되는지 궁금합니다. 코드를 자세하게 설명해주시면 너무 감사하겠습니다.마감일이 얼마 안남았는데 덕분에 한 발짝 성장했습니다.





친절하게 답변해주셔서 감사합니다.

@mrhan1

thymleaf 를 사용해 보지 않아서 정확히는 말씀드릴 수가 없는데;
대부분의 템플릿 언어들의 사용방식은 비슷합니다.

  1. 서버에서 특정Path접속시 컨트롤러가 받고, 데이터처리를 한후 Model 생성
  2. 렌더링된 뷰에 데이터를 내림
  3. 서버에서 해당 Model과 같이 서버에서 렌더링 (SSR)
  4. 이 렌더링한 결과를 브라우저에서 다운받아 실행

즉 템플릿 언어를 사용한다는 것은 SSR을 사용하는 것이라, 해당 템플릿 언어가 지원하는 문법 규칙만 맞춘다면 별 문제 없이 동작할거에요.

질문 주신 것처럼 CDATA로 묶은 부분이 제대로 동작하는지는
브라우저에서 소스보기나, 개발자도구의 DOM Tree 부분을 보시면 확인이 가능합니다. SSR(서버 사이드 렌더링)이기 때문에 ${XXXX} 와 같은 것은 모두 데이터로 변경되어 있을 것이거든요.
그래서 이렇게 확인하면 됩니다. 아마 별문제없이 브라우저에서 해당 스크립트들이 동작했다면, 템플릿엔진은 잘 렌더링 된거라고도 볼 수 있구요.

그리고 두번째 마커를 올리는 부분은, 네 저렇게 진행해도 괜찮을 것 같습니다. 마커 생성 부분이 function으로 묶여 있으니 var키워드를 사용해도 해당 function scope에 걸리기 때문에 그 안에서만 유효하기에 마지막 객체로 덮어쓰는 일은 없을 거에요.

그리고 아시겠지만 위처럼 생성을 하면 wrap이라는 객체가 하나만 만들어지는 것이라, 여러개를 만들고 싶으시다면 저 부분을 함수로 묶어서 실행하는 것을 추천드립니다.

한번 작업 해보시고 개발자 도구를 적극 활용해서 데이터를 추적해 보셔도 됩니다.

그리고 이건 제 개인적인 스타일이긴 한데, 스크립트 로직안에 템플릿 언어가 개입하는 것을 개인적으로는 추후 유지보수의 어려움이나 모듈화를 방해하는 요소가 되기에, 서버에서 REST API형식으로 데이터를 제공할 수 있게 하고 클라이언트에서는 AJAX통신을 통해서 데이터를 가져오거나, 이렇게 할 수 없는 환경이라면, 데이터만 따로 최상단에 별도로 스크립트 객체로 만들고, 그 아래에서는 그 데이터 객체를 사용하는 방식으로 하면, 데이터를 받는 주체와, 이를 가지고 이용을 하는 주체가 달라지기 때문에 코드가 좀더 보기쉽고 추후 기능추가도 좀더 편하실 것 같습니다.

일단 CDATA를 이용하는 저 주석자체가 코드를 읽거나 수정할때 햇갈릴 수 있기 때문에 이 부분을 한곳에 몰아서 데이터 처리를 하고, 나머지는 순수 자바스크립트로만 구성하시는게 추후 기능 추가를 하실때 더 편하실 거라 봅니다.
이렇게 나누는 것도 서버에서 View-Model-Controller가 나뉘듯이, 클라이언트도 이 구조를 따라서 만드는게 추후 확장성에서 더 좋기 때문입니다.

//여기는 템플릿으로 부터 데이터를 넣는 부분
/*<![CDATA[*/ 
var serverData = {
   address : /*[[address.address]]*/,
   position: [/*[[address.lattitude]]*/,/*[[address.longitude]]*/]
  .......
}
/*]]>*/

//아래부터는 스크립트 로직만
function createOverlayContent() {
   .....
   const address = document.createTextNode(serverData.address);
   .....
   const position = new kakao.maps.LatLng(serverData.position[0], serverData.position[1]);
   ....
   return wrap;
}

이렇게 하는게 추후 코드를 보시거나, 정리를 하실때 더 편하실 거라 생각이 듭니다.

한번 참고해 보세요.