vuetify-admin
vuetify-admin copied to clipboard
FetchJSON / FetchHydra providers don't support file uploads
When using the FetchJSON or FetchHydra (which mostly inherits from it) providers there is no support for file uploads.
These providers use JSON.stringify() to get form data and send the result to the server using HTTP Fetch. This results in request bodies such as { file: {} }
when using a va-file-input field in a create/edit form.
In opposition, the Laravel provider uses FormData which does seem to support file uploads.
@nonsintetic Did you figure out this by any chance? Doesn't the vuetify-admin provide objectToFormData utility, which can be utilized for this task?
@rokmy it does, but you essentially have to write your own data provider for that to work. You could use the Laravel provider and adapt it for json/hydra APIs for example, the principle is the same (using FormData to support file attachments and sending that with Fetch to the server).
If I do get around to writing a better provider I'll be sure to submit a pull request, I seem to be using VA for a lot of things these days.
Due to time crunch and only needing it for a single thing, I just wrote a separate method to upload that particular file at the moment.
Would you be able to share the code snipper for the upload? I've had success while hardcoding a listener in one of the CRUD pages (Create.vue) for the form, but it seems like a very messy solution.
The thing I'm working on now, is modifying the hydra provider (hydra.js)
let data = objectToFormData(params.data);
const formdata = new FormData();
formdata.append('file', params.data.file);
httpClient.post(`${resource}`, formdata)
},
but the upload payload seems to be empty.
<template>
<va-create-layout>
<v-form ref="form">
<v-file-input
v-model="file"
accept="image/*,.pdf"
label="Upload file"
></v-file-input>
<v-btn
:disabled="!file"
color="success"
class="mt-4"
@click="send"
>
Upload
</v-btn>
</v-form>
</va-create-layout>
</template>
<script>
export default {
props: ["id", "item"],
data() {
return {
file: null,
};
},
methods: {
send() {
let self = this;
//assemble headers
let headers = new Headers({
Accept: "application/ld+json",
});
let token = localStorage.getItem("jwt_token");
if (token) {
headers.set("Authorization", `Bearer ${token}`);
}
//assemble form data
var data = new FormData();
data.append("file", this.file);
//if you have other fields, here is where you'd add them to the data object
//send request to api
//"this.$admin.http.url" - a way to get the URL of your api as set in the admin.js file
fetch(this.$admin.http.url + "/files", {
method: "POST",
headers: headers,
body: data,
})
.then((response) => response.json())
.then(function (response) {
if (response["@id"]) {
//this signals to VA that the item was saved successfully
self.$emit("saved");
}
});
//TODO: lol error handling
},
},
};
</script>
Regarding your example, objectToFormData()
already returns a FormData object, so you can just pass it the object that contains the fields and data, then send what it spits out as the body of your request.
Thanks so much, I've modified hydra.js file to make it more dynamic, and it seems to be working for the specific use case. I will make some case switch statements later on.
const formdata = new FormData();
formdata.append('file', params.data.file);
console.log(formdata.getAll('file'))
let headers = new Headers({
Accept: "application/ld+json",
});
fetch('url', {
method: "POST",
headers: headers,
body: formdata
})
.then((response) => response.json)
.then(function (response) {
console.log(response)
})
Thanks so much for the help!