Reputation: 7947
I have a ajax wrapper functions in my project. I'll be calling this wrapper function to perform ajax requests in my application. Now I'm planning to change this to use fetch. But since I'm new I got some questions inside me. I believe this question we helpful to people who is planning to move from Jquery Ajax to Fetch. Here is the code and questions.
My old Jquery Ajax wrapper function:
function ajaxGetAsync(requestUrl, postData, global, datatype) {
try {
var form = $('#__AjaxAntiForgeryForm');
var token = $('input[name="__RequestVerificationToken"]', form).val();
return $.ajax({
type: "GET",
cache: false,
contentType: "application/json; charset=utf-8",
dataType: datatype,
url: requestUrl,
async: true,
global: global,
headers: {
"XSRF-TOKEN": $('#_AjaxAntiForgeryTokenForm input[name="__RequestVerificationToken"]').val()
},
data: postData,
error: function (jqXhr, textStatus, errorThrown) {
console.log(jqXhr);
handleShowInformationBox('Error', errorThrown, 'OK');
}
});
} catch (q) {
ajaxIndicatorStop();
}
return false;
};
function ajaxFormPostAsync(requestUrl, form, global = true) {
try {
return $.ajax({
type: "POST",
url: requestUrl,
async: true,
global: global,
headers: {
"XSRF-TOKEN": $('#_AjaxAntiForgeryTokenForm input[name="__RequestVerificationToken"]').val()
},
data: new URLSearchParams(new FormData(document.querySelector(form))).toString(),
success: function () {
handleHideValidationErrors(form);
},
error: function (jqXhr, textStatus, errorThrown) {
console.log(jqXhr);
handleShowInformationBox('Error', errorThrown, 'OK');
}
});
} catch (q) {
ajaxIndicatorStop();
}
return false;
};
Here is how I configured Ajax Globals for displaying/hiding loaders:
$(document).ajaxStart(function () {
ajaxIndicatorStart('Loading');
});
$(document).ajaxStop(function () {
ajaxIndicatorStop();
});
Now i call the above method to Get HTML/JSON from server as follows,
$.when(ajaxGetAsync(url, { id: Id }, true, window.htmlDataType)).done((response) => {
document.querySelector('#someDiv').innerHTML = response;
});
$.when(ajaxPostAsync(url, { id: Id }, true, window.jsonDataType)).done((response) => {
console.log(response);
});
Note that I'll change datatype to window.jsonDataType
to get json data. Similarly I call my ajaxFormPostAsync
This works fine.
Here is the fetch equivalent:
My new Fetch wrapper function:
async function fetchGetAsync(requestUrl, postData, global, dataType) {
return await fetch(requestUrl,
{
method: 'GET',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json; charset=utf-8',
"XSRF-TOKEN": $('#_AjaxAntiForgeryTokenForm input[name="__RequestVerificationToken"]').val()
},
body: postData
}
).catch(function (error) {
console.log(error);
handleShowInformationBox('Error', error, 'OK');
});
}
async function fetchFormPostAsync(requestUrl, form, global) {
return await fetch(requestUrl,
{
method: 'POST',
cache: 'no-cache',
headers: {
"XSRF-TOKEN": $('#_AjaxAntiForgeryTokenForm input[name="__RequestVerificationToken"]').val()
},
body: new FormData(document.querySelector(form))
})
.then(function (response) {
return response.json();
})
.catch(function (error) {
handleShowInformationBox('Error', error, 'OK');
});
}
How to configure globals to display/hide loaders? How to specify datatype in fetch api?
I tried calling the above method as follows,
await fetchGetAsync(url, { id: Id }, true, window.htmlDataType).then((response) => {
document.querySelector('#someDiv').innerHTML = response;
})
await fetchFormPostAsync(url, targetForm).then(function (response) {
console.log(response);
});
This throws error as shown below:
For GET:
TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.
For POST:
Unexpected end of JSON input
How to get Json/Html using fect api like how I did previously?
Just started learning fetach api with my existing code. Please assist on where I go wrong.
Upvotes: 3
Views: 1182
Reputation: 7947
After some learning and works, Here is how I implemented fetch
API wrappers in my project along with showing/hiding spinners and removed ajax
wrappers.
Fetch GET wrapper:
async function fetchGetAsync(requestUrl, postData, global, dataType) {
let query = Object.keys(postData)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(postData[k]))
.join('&');
requestUrl = `${requestUrl}?${query}`;
if (global) ajaxIndicatorStart('Loading');
return await fetch(requestUrl,
{
method: 'GET',
cache: 'no-cache',
headers: {
"XSRF-TOKEN": document.querySelector('input[name="__RequestVerificationToken"]').value
}
})
.then((response) => {
return dataType === window.constant.jsonDataType ? response.json() : response.text();
})
.catch((error) => {
handleShowDefaultInformationBox(error, 'OK');
})
.finally(() => {
if (global) ajaxIndicatorStop();
});
}
Fetch POST wrapper:
async function fetchFormPostAsync(requestUrl, form, global = true) {
if (global) ajaxIndicatorStart('Loading');
return await fetch(requestUrl,
{
method: 'POST',
cache: 'no-cache',
headers: {
"XSRF-TOKEN": document.querySelector('input[name="__RequestVerificationToken"]').value
},
body: new URLSearchParams(new FormData(document.querySelector(form)))
})
.then((response) => {
return response.json();
})
.catch((error) => {
handleShowDefaultInformationBox(error, 'OK');
})
.finally(() => {
if (global) ajaxIndicatorStop();
});
}
similarly you can construct fetch
API wrappers for other HTTP verbs and actions.
Then call from your javascript like shown below:
Calling Fetch GET wrapper:
await fetchGetAsync(url, { id: Id }, true, window.constant.htmlDataType).then((response) => {
document.querySelector('#someDiv').innerHTML = response;
})
Calling Fetch POST wrapper:
await fetchFormPostAsync(url, targetForm).then((response) => {
console.log(response);
});
Thanks to charlietfl and Icepickle for guidance and support.
Upvotes: 3