Reputation: 129
I need to send an object including a base64-encoded image to an API-endpoint in TS. I use this code to convert a file to Base64 and attach it to an object:
const file = values.beleg1;
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = async function () {
const result = reader.result.toString().split(',')[1];
await valuesObj.push({ name: 'base64Image', value: result });
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
If I then log the object 'valuesObj' it does show that the base64-object is attached to the main-object.
However when I then I then use this object in the request like in the code below it is not shown in the payload when looking at the network-request
axios({
url: 'http://localhost:8080/createPDF',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
responseType: 'blob',
data: valuesObj,
})
.then((response: AxiosResponse) => {
setLoadingText('');
const blob: Blob = new Blob([response.data], { type: 'application/pdf' });
const objectUrl: string = window.URL.createObjectURL(blob);
window.open(objectUrl);
})
.catch((error) => {
console.log(error);
});
What is the reason for this? Does it have anything to do with the length/size of the string? Or is there another reason?
Upvotes: 1
Views: 1505
Reputation: 192
Your Problem seems to be that your async axios request gets the value of your valuesObj, before onload actually adds your new record.
Sorry forgot a solution ^^
Either you put your axios request directly into the pipe...
reader.onload =
(async function () {
const result = reader.result.toString().split(',')[1]
await valuesObj.push({ name: 'base64Image', value: result})
return valuesObj
})
.then(
data =>
axios({
url: 'http://localhost:8080/createPDF',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
responseType: 'blob',
data,
})
.then((response: AxiosResponse) => {
setLoadingText('')
const blob: Blob = new Blob([response.data], { type: 'application/pdf' })
const objectUrl: string = window.URL.createObjectURL(blob)
window.open(objectUrl)
})
.catch(console.log))
)
})
or you create another async function which you can call from your onload or from another async fn, which awaits both async events.
Upvotes: 0
Reputation: 209625
What is happening is the reader hasn't finished reading before the Axios call proceeds. The reader executes asynchronously. Thus, the order of operations often ends up something like this:
onloaded
.Because you aren't waiting for the load event to finish before sending the Axios request, the request does not include the new data. You need to make sure the load event is finished and the data is pushed onto your array before you proceed with the Axios call.
try {
const file = values.beleg1;
const reader = new FileReader();
reader.readAsDataURL(file);
// construct a promise that will resolve once loading is complete,
// and then wait for it, so that we don't make the axios call until
// after the loading is done.
await new Promise<void>((resolve, reject) => {
reader.onload = function () {
const result = reader.result.toString().split(',')[1];
valuesObj.push({ name: 'base64Image', value: result });
// notify that the promise has completed its work
resolve();
};
reader.onerror = function () {
// notify that the promise failed and pass along the error object
reject(reader.error);
};
});
// I picked any since I don't want to define out the full type, but you probably should
const response: any = await axios({
url: 'http://localhost:8080/createPDF',
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
responseType: 'blob',
data: valuesObj,
});
setLoadingText('');
const blob: Blob = new Blob([response.data], { type: 'application/pdf' });
const objectUrl: string = window.URL.createObjectURL(blob);
window.open(objectUrl);
} catch (error) {
// all errors during the processing are caught in one place
console.log('Error: ', error);
}
Note that I put everything in async/await style, except the required Promise
object, and I have a single try-catch block. If you want to process errors at a higher level of granularity, split it into multiple try-catch blocks.
When we make sure to await every asynchronous action, we ensure that we don't start the next one until we are done with the previous, so everything is done in order.
Upvotes: 2