Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

FetchJSON / FetchHydra providers don't support file uploads #31

Open
nonsintetic opened this issue Nov 16, 2021 · 5 comments
Open

FetchJSON / FetchHydra providers don't support file uploads #31

nonsintetic opened this issue Nov 16, 2021 · 5 comments

Comments

@nonsintetic
Copy link

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.

@rokmy
Copy link

rokmy commented Nov 18, 2021

@nonsintetic Did you figure out this by any chance?
Doesn't the vuetify-admin provide objectToFormData utility, which can be utilized for this task?

@nonsintetic
Copy link
Author

nonsintetic commented Nov 18, 2021

@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.

@rokmy
Copy link

rokmy commented Nov 18, 2021

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.

@nonsintetic
Copy link
Author

nonsintetic commented Nov 18, 2021

<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.

@rokmy
Copy link

rokmy commented Nov 18, 2021

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!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants