window.onload() 중복 실행 불가 문제
[오류 개선]
base.html과 base.html을 extend 하는 템플릿 두 파일에서 window.onload()를 실행할 경우 가장 마지막에 실행한 함수만 실행되고 나머지는 무시된다.
따라서 addListener 메서드를 이용해서 두 탬플릿 모두 load 이벤트가 발생했을 때 함수를 실행할 수 있도록 구현했다.
window.addEventListener("load", isLogin());
window.addEventListener("load", async function PageLoad() { ... }
게임 생성 페이지 구현
[기능 구현]
페이지의 form 태그는 아래와 같이 작성했다.
<form method="POST" enctype="multipart/form-data" id="game_create_form" onsubmit="GameCreate(event);">
{% csrf_token %}
<div>
<label for="id_title">제목: </label>
<input type="text" name="title" maxlength="50" required="" id="id_title">
</div>
<div>
<label for="id_content">게임 설명: </label>
<textarea name="content" cols="40" rows="10" required="" id="id_content"></textarea>
</div>
<div>
<label for="id_gamefile">게임 파일: </label>
<input type="file" name="gamefile" accept="application/zip" id="id_gamefile">
</div>
{# 태그#}
<div>
<label for="id_thumbnail">썸네일: </label>
<input type="file" name="thumbnail" accept="image/*" id="id_thumbnail" alt="...">
</div>
<div>
<label for="id_youtube_url">유튜브 링크: </label>
<input type="text" name="youtube_url" maxlength="50" required="" id="id_youtube_url">
</div>
<div>
<label for="id_screenshots">스크린샷: </label>
<input type="file" name="screenshots" accept="image/*" id="id_screenshots" alt="..." multiple>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="submit" class="btn btn-primary">완료</button>
</div>
</form>
POST 요청이므로 method 속성값을 POST로 했다.
파일 업로드가 포함된 form이기 때문에 enctype 속성을 추가했다.
onsubmit 속성을 추가하여 form이 제출되는 이벤트가 발생했을 때(onsubmit) GameCreate() 함수가 실행되도록 했다.
POST 요청이므로 csrf 토큰을 form에 포함했다.
api 함수에서 request 데이터로부터 호출할 key와 각 input 태그의 name 속성값이 일치하도록 했다.
button의 type 속성을 submit으로 설정했다. 그래서 button을 클릭할 때 onsubmit 이벤트가 발생하여 GameCreate() 함수가 실행된다.
<script>
async function GameCreate(event) {
event.preventDefault(); // 폼의 기본 제출 동작을 방지
const form_tag = document.getElementById('game_create_form');
const formData = new FormData(form_tag);
const url = '{% url 'games:game_list' %}'
try {
await aSend({
url: url,
method: 'POST',
is_token: true,
body: formData
})
} catch (error) {
console.error('Error:', error);
return false;
}
window.location.href = "{% url 'test_main_view' %}";
}
</script>
해당 함수에서는 form 태그의 기본 동작(form 제출 후 페이지 리로드(새로고침))을 하지 않도록 event.preventDefault(); 를 통해 제어했다.
그 다음 form tag 요소 자체의 data를 인자값으로 받는 FormData 인스턴스를 생성하여 aSend 함수의 body 인자값으로 넘긴다.
aSend 가 잘 실행이 되었을 경우 try 안의 코드만 실행 후 메인 페이지로 리다이렉트 하지만 오류가 발생할 경우 catch 문에 의해 error를 출력한다.
aSend() 는 extend 하는 탬플릿인 base.html에 정의된 함수이며 아래와 같다.
async function aSend({url, method, is_token, body = null}) {
const headers = {};
if (is_token) {
await tokenRefresh();
const access = localStorage.getItem('access_token');
headers['Authorization'] = `Bearer ${access}`
}
const data = {
method: method,
headers: headers,
}
if (body) {
data["body"] = body
}
const response = await fetch(`${url}`, data);
return response.json();
}
url, method, is_token, body를 파라미터로 하는 비동기 함수이며
각 파라미터의 인자값에 따라 fetch() 함수로 각기 다른 api 요청을 보내고 그에 따른 response를 json 형태로 리턴한다.
base.html을 extend 하는 모든 탬플릿은 해당 함수를 이용하여 api 요청을 수행할 수 있도록 했다.
is_token 인자 값이 true 라면 header의 Authorization 값으로 access 토큰 값을 포함하여 전송한다.
기본적으로 api 요청엔 method와 headers를 포함하지만 body 파라미터의 인자값이 존재할 경우 body를 같이 포함하여 요청한다.
fetch()를 실행할 땐 await 구문을 통해 동기적 처리를 하도록 유도하였다.
다만 headers를 기본적으로 비워두고 있는 상태인데, api 요청 형태에 따라 headers 옵션을 따로 설정해주는, 분기 처리해주는 부분이 필요하다는 의견이 있어 추후(다음주 월요일(24년 5월 27일)) 적용할 것이다. 예시는 아래와 같다.
async function aSend({url, method, is_token, body = null}) {
const headers = {};
if (!(body instanceof FormData)) {
headers['Content-Type'] = 'application/json';
}
'프로젝트' 카테고리의 다른 글
[TIL] 20240528 72일차 (0) | 2024.05.28 |
---|---|
[TIL] 20240527 71일차 (0) | 2024.05.27 |
20240520 ~ 20240524 14주차 정리 (0) | 2024.05.24 |
[TIL] 20240523 69일차 (0) | 2024.05.23 |
[TIL] 20240522 68일차 (0) | 2024.05.22 |