ajax 요청을 간편하게 > 그누보드5 팁자료실

그누보드5 팁자료실

ajax 요청을 간편하게 정보

ajax 요청을 간편하게

본문

매번 ajax 요청 코드를 작성하는 게 귀찮아서 함수로 만들어서 사용 중입니다.

필요하다면 상황에 맞게 수정하셔서 사용하시면 되지 싶습니다.
 


const App = window.App || {};
App.callbacks = {};
document.addEventListener('DOMContentLoaded', function () {
    addProgressStyles();
    addProgressElement();
    document.addEventListener('click', handleButtonClick);
});
function addProgressStyles() {
    const style = document.createElement('style');
    style.textContent = `
        #progress { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 9999; overflow: hidden; background: #000; opacity: .1; }
        #progress:after { content: ""; position: fixed; top: calc(50% - 30px); left: calc(50% - 30px); border: 6px solid #60718b; border-top-color: #fff; border-bottom-color: #fff; border-radius: 50%; width: 60px; height: 60px; animation: animate-progress 1s linear infinite; }
        @keyframes animate-progress {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    `;
    document.head.appendChild(style);
}
function addProgressElement() {
    const progress = document.createElement('div');
    progress.id = 'progress';
    document.body.appendChild(progress);
}
function handleButtonClick(event) {
    if (event.target.classList.contains('btn-form-submit-ajax')) {
        handleAjaxFormSubmit(event.target);
    }
}
// 상황에 맞게 수정하거나 삭제
const API_BASE_URL = window.API_FULL_BASE_URL || '/api/v1';
let cachedCsrfToken = null;
// CSRF 토큰을 가져오는 함수 //상황에 맞게 수정하거나 삭제
async function getCsrfToken() {
    if (cachedCsrfToken) return cachedCsrfToken;
    
    try {
        const response = await fetch(`${API_BASE_URL}/token/getUserCsrfToken`);
        if (!response.ok) throw new Error('Failed to fetch CSRF token');
        const data = await response.json();
        if (!data.token) throw new Error('CSRF token not found in response');
        cachedCsrfToken = data.token;
        return cachedCsrfToken;
    } catch (error) {
        console.error('Error fetching CSRF token:', error);
        throw error;
    }
}
// CSRF 토큰을 초기화하는 함수
function resetCsrfToken() {
    cachedCsrfToken = null;
}
// AJAX 요청을 보내는 함수
async function sendAjaxRequest(method, url, data, isFormData = false, isLoading = false, retryCount = 0) {
    try {
        // CSRF 토큰 관련 함수 및 아래 부분에 상황에 맞게 수정하거나 삭제
        const csrfToken = await getCsrfToken();
        const options = {
            method,
            headers: {
                'X-CSRF-Token': csrfToken
            }
        };
        if (method.toUpperCase() !== 'GET') {
            if (isFormData && data instanceof FormData) {
                options.body = data;
            } else if (!isFormData) {
                options.headers['Content-Type'] = 'application/json';
                options.body = JSON.stringify(data);
            } else {
                throw new Error('Invalid data type for isFormData=true');
            }
        } else if (data) {
            url += (url.includes('?') ? '&' : '?') + new URLSearchParams(data).toString();
        }
        if (isLoading) toggleProgress(true);
        const response = await fetch(url, options);
        const responseData = await response.json();
        if (isLoading) toggleProgress(false);
        if (!response.ok) {
            if (response.status === 419 && retryCount < 3) { // CSRF 토큰 만료 시 반환하는 상태 코드, 최대 3번 재시도
                //console.log('CSRF 토큰이 만료되어 새로운 토큰을 요청합니다.');
                resetCsrfToken();
                // 재귀적으로 동일한 요청을 다시 시도
                return sendAjaxRequest(method, url, data, isFormData, isLoading, retryCount + 1);
            }
            throw new Error(responseData.error || 'Request failed');
        }
        return responseData;
    } catch (error) {
        handleError(error);
        return Promise.reject(error); // 호출한 곳으로 에러 전달
    }
}
// AJAX 폼 제출 처리 함수
async function handleAjaxFormSubmit(button) {
    const form = button.closest('form');
    const url = button.getAttribute('data-target');
    const beforeSubmitFunctionName = button.getAttribute('data-beforesubmit');
    const callbackFunctionName = button.getAttribute('data-callback');
    const loading = button.getAttribute('data-loading') === 'true';
    // 폼 전송 전 함수 실행
    if (beforeSubmitFunctionName) {
        const shouldProceed = await executeCallback(beforeSubmitFunctionName);
        if (!shouldProceed) {
            return; // beforeSubmit 함수가 false를 반환하면 폼 전송 중단
        }
    }
    // TinyMCE 에디터 내용 저장 - 타에디터 사용 시 해당 에디터에 맞게 수정.
    document.querySelectorAll('.editor-form').forEach(editor => {
        if (tinymce.get(editor.id)) {
            tinymce.get(editor.id).save();
        }
    });
    if (!validateForm(form)) return; // 폼을 체크하는 함수, 삭제 후 사용
    button.disabled = true;
    try {
        const formData = new FormData(form);
        const data = await sendAjaxRequest('POST', url, formData, true, loading);
        if (data.result === "success") {
            if (callbackFunctionName) {
                executeCallback(callbackFunctionName, data);
            }
        } else {
            alert('오류: ' + (data.message || '알 수 없는 오류가 발생했습니다.'));
        }
    } catch (error) {
        handleError(error);
    } finally {
        button.disabled = false;
    }
}
 
async function sendCustomAjaxRequest(method, url, data, loading = false, callbackFunctionName = null) {
    try {
        const responseData = await sendAjaxRequest(method, url, data, false, loading);
        if (callbackFunctionName) {
            executeCallback(callbackFunctionName, responseData);
        }
        return responseData;
    } catch (error) {
        handleError(error);
        return Promise.reject(error);
    }
}
// 콜백 함수 실행
function executeCallback(callbackFunctionName, data) {
    if (typeof App.callbacks[callbackFunctionName] === 'function') {
        App.callbacks[callbackFunctionName](data);
    }
}
// 에러 핸들러
function handleError(error) {
    const errorMessage = error.message || '알 수 없는 오류가 발생했습니다.';
    if (errorMessage.includes('CSRF 토큰이 만료되었습니다')) {
        console.error(errorMessage);
    } else {
        console.error('Error: ' + errorMessage);
    }
}
// 프로그레스 표시 토글 함수
function toggleProgress(show = true) {
    const progress = document.getElementById('progress');
    if (progress) progress.style.display = show ? 'block' : 'none';
}
function prettyPrintJson(data) {
    console.log(JSON.stringify(data, null, 2));
}
// 콜백 함수 등록
App.registerCallback = function(name, callback) {
    if (typeof callback === 'function') {
        App.callbacks[name] = callback;
    } else {
        //console.error(`Invalid callback function for ${name}`);
    }
};
 


## 폼 전송 시
<form name="frm" id="frm" enctype="multipart/form-data">
<!-- form html --->
<button type="button" value="확인"  data-target="url경로" data-beforesubmit="beforeSubmit" data-callback="fnCallback">확인</button>
</form>

## 폼 이외 전송 시
<button type="button" value="확인" onclick="submitAjax();">확인</button>

<script>

function submitAjax() {
    var data = {data1:data1, data2:data2}; //전송할 데이터
    var url = '/ajax.php'; //ajax 파일 경로

    try {
       const result = await sendCustomAjaxRequest('POST', url, data, true, 'customFnCallback');
    }
    catch (error) {
        alert('순위 검색에 실패했습니다: ' + (error.message || '알 수 없는 오류'));
    }
}

// ajax 전송 전 또는 전송 후 실행할 함수 , 물론 함수명은 샘플임.
App.registerCallback('beforeSubmit', function(data) {
    console.log(data);
});

App.registerCallback('fnCallback', function(data) {
    console.log(data);
});

App.registerCallback('customFnCallback', function(data) {
    console.log(data);
});

</script>

추천
9

댓글 5개

전체 7 |RSS
그누보드5 팁자료실 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1402호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT