코딩하는라민

[Javascript] confirm 후 clipboard api 사용 시 DOMException Error 발생하는 문제점 본문

Core/JavaScript

[Javascript] confirm 후 clipboard api 사용 시 DOMException Error 발생하는 문제점

코딩하는라민 2023. 12. 19. 17:54
728x90
반응형

[Javascript] confirm() 후 clipboard api 사용 시 TypeError 발생

 

📌 confirm 후 clipboard api 사용 시 에러

 

[JavaScript/React] 현재 URL 복사하기 & window.location 객체

[JavaScript/React] 현재 URL 복사하기 & window.location 객체 프로젝트를 진행하면서 페이지의 url 을 사용자에게 공유하는 기능을 구현하게 되었다. 그러면서 알게된 것이 바로 window.location 객체이다. windo

ramincoding.tistory.com

지난번 포스팅에서 window.location 객체와 cilpboard api 를 이용해 현재 url 을 복사하는 로직을 구현했었다.

버튼을 누르자마자 url 을 복사했었는데, 요구사항이 추가됨에 따라서 팝업창을 띄우고 나서 해당 복사를 실행하는 것으로 로직이 변경되었다.

 

confirm 창을 띄우고 [확인] 버튼을 누르면 다른 기능을 실행하고, [취소] 버튼을 누르면 현재 url 을 복사한다.

 

하지만 문제가 발생했다.

confirm 창을 띄우면 clipboard api 의 catch 문이 실행되는 것이었다.

콘솔창에 error 를 출력해보면 다음과 같다.

 

DOMException 에러
const link = window.location.href;

const handleCopyButton = () => {
  confirm('복사하시겠습니까?') &&
    try {
      await navigator.clipboard.writeText(shareLink);
      alert('성공!');
    } catch (err) {
      alert('실패!');
      console.error(err);
    }
};

 

📌 왜 이런 에러가 발생하는 것일까?

DOMException: Document is not focused

이것은 비동기 작업이 특정 환경에서 실행되지 못해 발생하는 에러 메세지이다.

 

이 특정 환경이 무엇이냐면,

버튼을 클릭하면 confirm 창을 띄우고  url 을 클립보드에 저장하는 코드가 실행된다고 하자.

우리는 confirm 창의 확인 혹은 취소를 누를 것이며,

이 때 이벤트의 주체가 문서가 아닌 브라우저의 다이얼로그창이 되어버린다.

 

즉, clipboard api 작업이 실행될 때  현재 문서(Document)가 포커스를 잃은 상태가 된다.

이로인해 clipboard api 의 작동에 문제가 생길 수 있다.

clipboard 는 document 에서 실행되는 이벤트이고, 정상적으로 기능을 수행하려면 focus 를 다시 document 로 가져와야 하는 것이다.

 

📌 window.focus()

window.focus() 는 DOM 에서 사용되는 메서드로 주어진 요소에 포커스를 설정해준다.

우리는 confirm 창으로 옮겨간 포커스를 다시 현재 문서로 가져와야 하는 걸까?

 

아니다!

window.focus 는 현재 창에 다시 포커스를 주기 위한 명령이다.

confirm 창이 닫히면 다시 포커스가 문서로 돌아온다.

따라서 이 명령어 대신 지연하여 코드를 실행하는 방식으로 충분히 문제를 해결할 수 있다.

 

📌 clipboard api 지연 실행

setTimeout

clipboard api 를 지연해서 실행하기 위해 setTimeout 을 사용했다.

const link = window.location.href;

// confirm 후 클립보드 복사 실행
const handleCopyButton = () => {
  const confirmMessage = confirm('현재 url을 복사할까요?');

  if (confirmMessage) {
    setTimeout(async () => {
      await copyClipboard();
    }, 500);
  }
};

// 클립보드 복사 함수
const copyClipboard = async () => {
  try {
    await navigator.clipboard.writeText(shareLink);
    alert('성공!');
  } catch (err) {
    alert('실패!');
  }
};

 

확인해보면 다음과 같이 정상적으로 api 연결이 성공한다.

 

728x90
반응형