pqina / filepond

🌊 A flexible and fun JavaScript file upload library
https://pqina.nl/filepond
MIT License
15.15k stars 825 forks source link

how to populate initial files from remote URLs #192

Closed pravinfullstack closed 5 years ago

pravinfullstack commented 5 years ago

I have successfully uploaded the files over the server with this plugin, now i want to display the already uploaded files ( residing on S3 bucket). Even if i use :files property, i dont get a preview of the image. So my question is, what is the best way to display the uploaded images/URL ?? (in my case AWS S3 url)

<file-pond
        name="filepond"
        ref="pond"
        class="user-profile-picture"
        label-idle='Drag & Drop your files or <span class="filepond--label-action"> Browse </span>'

        dropValidation="true"
        instantUpload="false"    
        @processfile="updateFiles"
        :server="server"
        :files = myFiles
        /> 
return {
      myFiles: [{
          source: "https://www.google.com/logos/doodles/2018/baba-amtes-104th-birthday-6729609885253632-s.png",
          options:{
                type: 'remote'
          }
      }],
}
rikschennink commented 5 years ago

Find more information on loading initial files here: https://pqina.nl/filepond/docs/patterns/api/filepond-object/#setting-initial-files

There is no type remote.

FilePond will try to load local files using the server.load end-point. See server docs for more information.

pravinfullstack commented 5 years ago

13

@rikschennink So, my files are located on remote server and i want to display them in file pond. I am using load method to display my remote files on firebase cdn. But i get the errors without a file preview. What wrong i am doing in this code? Although Upload is working successfully

<template>
  <div id="app">

    <file-pond
        name="filepond"
        ref="pond"
        label-idle='Drag & Drop your files or <span class="filepond--label-action"> Browse </span><br> <b>Maximum 5 files upload</b>'
        allow-multiple="true"
        imagePreviewMaxFileSize="1MB"
        imagePreviewHeight="100"
        instantUpload="true"
        max-files="5"
        dropOnElement="false"
        allowFileTypeValidation="true"
        dropOnPage="false"
        :server="server"
        :files = myFiles
        dropValidation="true"
        accepted-file-types="image/jpeg, image/png
        v-on:init="handleFilePondInit"       
        @processfile="updateFiles"
        :allowImageTransform="false"
        /> 

  </div>
</template>

<script>
// Import Vue FilePond
import vueFilePond from "vue-filepond";

// Import FilePond styles
import "filepond/dist/filepond.min.css";
import firebase from "firebase";

// Import image preview plugin styles
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css";

// Import image preview and file type validation plugins
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";

// Create component
const FilePond = vueFilePond(
  FilePondPluginFileValidateType,
  FilePondPluginImagePreview
);
const userID = window.$cookies.get("uid")

export default {
  name: "multiple-file-uploads",
  components: {
    FilePond
  },
  },
  data: function() {
    return {
      myFiles:[{
        source:"https://firebasestorage.googleapis.com/v0/b/tradeon-main.appspot.com/o/product_photos%2F5ba67faefe791907942c2d96%2Fc3e6c0bf-ec5f-25db-09ec-cfbe982498cd?alt=media&token=f9afc39b-5a2a-43d7-bf23-66b07919964e",
        options: {
                type: 'local'
            }
      }],
      myFiless: [],
      server: {
        load: (source, load, error, progress, abort, headers) => {
            // Should get a file object from the URL here
            // ...
            console.log(source)            
            // Should call the progress method to update the progress to 100% before calling load
            // (computable, loadedSize, totalSize)
            progress(true, 0, 1024);

            // Should call the load method with a file object when done
            load(source)

            // Should expose an abort method so the request can be cancelled
            return {
                abort: () => {
                    // Let FilePond know the request has been cancelled
                    abort();
                }
            };
        },
        process: (fieldName, file, metadata, load, error, progress, abort) => {
          var uuid = guid();
          // File or Blob named mountains.jpg
          var file1 = file;
          // Create the file metadata
          var metadata = {
            contentType: "image/jpeg"
          };
          var storageRef = firebase.storage().ref();
          // Upload file and metadata to the object 'images/mountains.jpg'
          var uploadTask = storageRef
            .child("product_photos/" + "/" + userID + "/" + uuid)
            .put(file, metadata);
          // Listen for state changes, errors, and completion of the upload.
          // or 'state_changed'
          uploadTask.on(
            firebase.storage.TaskEvent.STATE_CHANGED,
            snapshot => {
              // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
              var progressTimer =
                snapshot.bytesTransferred / snapshot.totalBytes * 100;
              //console.log("Upload is " + progress + "% done");
              // Should call the progress method to update the progress to 100% before calling load
              // Setting computable to false switches the loading indicator to infinite mode
              progress(true, 1024, 1024);

              switch (snapshot.state) {
                case firebase.storage.TaskState.PAUSED: // or 'paused'
                  console.log("Upload is paused");
                  break;
                case firebase.storage.TaskState.RUNNING: // or 'running'
                  //console.log("Upload is running");
                  break;
              }
            },
            function(error) {
              // A full list of error codes is available at
              // https://firebase.google.com/docs/storage/web/handle-errors
              switch (error.code) {
                case "storage/unauthorized":
                  // User doesn't have permission to access the object
                  break;

                case "storage/canceled":
                  // User canceled the upload
                  break;
                case "storage/unknown":
                  // Unknown error occurred, inspect error.serverResponse
                  break;
              }
            },
            function() {
              // Upload completed successfully, now we can get the download URL
              uploadTask.snapshot.ref.getDownloadURL().then(downloadURL => {
                load(downloadURL);
                return {
                  abort: () => {
                    // Let FilePond know the request has been cancelled
                    abort();
                  }
                };
              });
            }
          );
        }
      }
    };
  },
  mounted(){
    console.log(this.myFiles)
  },
  methods: {
    handleFilePondInit: function() {
      return true;
    },
    updateFiles(error, file) {
      if (error) return false;
      this.myFiless.push(file.serverId);
      this.$emit("getFiles", this.myFiless);
    }
  }
};
function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return (
    s4() +
    s4() +
    "-" +
    s4() +
    "-" +
    s4() +
    "-" +
    s4() +
    "-" +
    s4() +
    s4() +
    s4()
  );
}
</script>
rikschennink commented 5 years ago

You probably have CORS errors in your developers console. Your server needs to either expose the correct CORS headers or you proxy your requests through your own server.

client => your server => firestore

When providing examples, please provide a compact test case and not a copy past of your code.

pravinfullstack commented 5 years ago

@rikschennink Apologies for lengthy code, if that created confusion, although that was not my intention. Now, I dont have any issue directing for CORS in my dev console. Could you kindly give an example to display initial files via load method, that will be very helpful

rikschennink commented 5 years ago

Looking at your load method again, I now see that you're returning the source value, this is the URL. FilePond expects a File object.

You can use fetch or XMLHttpRequest to turn the URL into a File object inside the server.load method.

pravinfullstack commented 5 years ago

@rikschennink Could you kindly direct me for an example? it will be helpful for future developers too. TIA

pravinfullstack commented 5 years ago

@rikschennink I tried to play with the code, i have already resolved my CORS issue, But now i get the following error

14 15

This is my files array

myFiles: [
        {
          source:
            "https://firebasestorage.googleapis.com/v0/b/tradeon-main.appspot.com/o/product_photos%2F5ba67faefe791907942c2d96%2Fc3e6c0bf-ec5f-25db-09ec-cfbe982498cd?alt=media&token=f9afc39b-5a2a-43d7-bf23-66b07919964e",
          options: {
            type: "local"
          }
        }
      ],

This is my load method,

    load: (source, load, error, progress, abort, headers) => {
          var url = source
          fetch(url) // Call the fetch function passing the url of the API as a parameter
          .then(function(e) {
              load(e.url);
          })
          .catch(function() {
              // This is where you run code if the server returns any errors
          });
          return {
                abort: (e) => {
                    // User tapped cancel, abort our ongoing actions here
                    console.log(e)
                    // Let FilePond know the request has been cancelled
                    abort();
                }
            };
        },
rikschennink commented 5 years ago

e.url is not of type Blob or File, it's a USVString (see MDN docs) so FilePond can't work with it. You have to return a Blob or File to the load method.

pravinfullstack commented 5 years ago

To anyone landing here with the similar problem, this is how its done @rikschennink Thank you for guidance

myFiles: [{
   source: remote url,
   options:{
          type: "local"
    }
}],
load: (source, load, error, progress, abort, headers) => {
            var myRequest = new Request(source);
            fetch(myRequest).then(function(response) {
              response.blob().then(function(myBlob) {
                load(myBlob)
              });
            });         
        },
foodaka commented 5 years ago

@maverickpravin i'm having trouble showing images in the preview from my s3 image bucket. I cant seem to load it in the preview from the external url. Any ideas?

  state = { files: [{ source: "https://s3-ap-northeast-1.amazonaws.com/sandbox-some-url/b50e6c1c-a49b-462d-a4c4-d3ca0d122423.jpg", options: { type: "local" } }]  }

  renderImageArea() {

    const serverConfig = {
      load: (uniqueFileId, load, error) => {
        console.log('uniqueFileId', uniqueFileId)
        fetch(uniqueFileId)
          .then(res => res.blob())
          .then(load)
          .catch(error)
      }
    };

    return (
      <FilePond
        ref={ref => (this.pond = ref)}
        files={this.state.files}
        allowMultiple={false}
        onupdatefiles={fileItems => {
          this.setState({
            files: fileItems.map(fileItem => fileItem.file)
          });
        }}
        server={serverConfig}
      />
    )
  }
foodaka commented 5 years ago

ah issue is on my side, when uploading image type to s3 was not the correct file format. Hence file preview on blob type was an empty string

zhil commented 5 years ago

for somebody, who is using XMLHttpRequest+custom headers in load - you may use code like

load: async (source, load, error, progress, abort, headers) => {
            const request = new XMLHttpRequest();
            request.open('GET', source)
            request.setRequestHeader('Authorization', await getTokenSilently());
            request.responseType = 'blob';

            request.onload = function () {
                if (request.status >= 200 && request.status < 300) {
                    load(request.response);
                } else {
                    // Can call the error method if something is wrong, should exit after
                    error('oh no');
                }
            };

            request.send();
        },
aavram commented 4 years ago

Im trying to load files from my server and load them in the files object of Filepond and then show them in my preview. I use the following code but my preview shows the name of the file but the size is incorrect. there is also an input type hidden with the correct url but i can't preview the file.


$.ajax({
                url: '@Url.Action("GetImagesForClaim", "Claims")?claimId=' + $('#claim-id').val(),
                type: 'GET',
                success: function (res) {
                    if (res.images.length != 0) {
                        var imagesArray = res.images;
                        imagesArray.forEach(function (item) {
                            var filePath = item.S3PreviewPath
                            var file = { source: filePath, options: { type: "local" } };
                            files.push(file);
                        });

                        console.log(files);
                        imagePond.setOptions({
                            server: {
                                load: {
                                url: '@Url.Action("GetImagesForClaim", "Claims")?claimId=' + $('#claim-id').val(),
                                method: "GET",
                                }
                            },
                            files: files,
                        });
                    }
                }
            })
ziming commented 4 years ago

Just curious when you load and show the already uploaded files, do the bar shows as green or grey? How to show it as green?

nizulzaim commented 3 years ago

ah issue is on my side, when uploading image type to s3 was not the correct file format. Hence file preview on blob type was an empty string

Hi, any advise from your side. I am not able to allow preview file at all. code kind of similar to yours however it is not working.

image

        load: async (source: any, load: any) => {
          console.log(source);
          var myRequest = new Request(source);
          fetch(myRequest).then(function (response) {
            response.blob().then(function (myBlob) {
              console.log(myBlob);
              load(myBlob);
            });
          });
        },
rikschennink commented 3 years ago

Make sure the mime type of your file is an image

nizulzaim commented 3 years ago

Make sure the mime type of your file is an image

Yeah. Thanks for that, I fixed it. Thank you again!

Make sure mimetype uploaded when using S3 correctly get from file object. Otherwise it will set as application/octet-stream

image

ryanzzeng commented 3 years ago

Just curious when you load and show the already uploaded files, do the bar shows as green or grey? How to show it as green?

Anyone know how to make it green? when the plugin load the uploaded file, it's grey color image

rikschennink commented 3 years ago

@ryanzzeng set type to 'limbo'

ryanzzeng commented 3 years ago

limbo

thanks @rikschennink , but after set type to 'limbo', when first loading, it will trigger onprocessfile, but that file is uploaded previously.

So both 'load' and 'process' will trigger event processfile ?

rikschennink commented 3 years ago

@ryanzzeng can you create a test case on codesandbox.io ?

ryanzzeng commented 3 years ago

hey @rikschennink , thanks i just created an example in codesandbox.io https://codesandbox.io/s/sweet-currying-dzj5k?file=/src/App.vue

If previously i have uploaded a file(id=1), and refresh the page, the file got uploaded again, but i only want to load the file . Currently it just trigger the process and file event processfile.

Is it possible to just load the previous uploaded files at initial stage? and if possible to removeFile() for the uploading file?

rikschennink commented 3 years ago

I don't understand what you mean. Looking at the example I don't see the functions as being implemented correctly, for example, the process function is missing a load callback.

See here for examples: https://pqina.nl/filepond/docs/api/server/#advanced

overclocked555 commented 3 years ago

To anyone landing here with the similar problem, this is how its done @rikschennink Thank you for guidance

myFiles: [{
   source: remote url,
   options:{
          type: "local"
    }
}],
load: (source, load, error, progress, abort, headers) => {
            var myRequest = new Request(source);
            fetch(myRequest).then(function(response) {
              response.blob().then(function(myBlob) {
                load(myBlob)
              });
            });         
        },

I am using this code, it works. Can I get the filename when uploading an image? Now filepond specifies the name 'image' for all images. In my case, the name matches the url and is also passed in the Content-Disposition header

image

rikschennink commented 3 years ago

@overclocked555 a Blob doesn’t have a name prop so FilePond won’t know the name (as you’re handling the file load yourself the content disposition header isn’t available for FilePond to read out).

Add a name prop to the Blob and it’ll work.

akshay-1707 commented 2 years ago

@overclocked555 hii is your issue resolved i m facing the same issue

akshay-17 commented 2 years ago

@overclocked555 can u please share u r file pond react code if possible

shrestharohit commented 1 year ago

how do i set serverId to the files loaded from URL I am using serverIds as a data to my backend and populating the filepond through URL from my backend database. Now for reordering files the serverID is set to the source url somehow.

This is how I am loading the files to filepond:

`imagesPond.setOptions({
  files: response.images.map((image) => ({
    source: image.file,
    // serverId: image.id,
    options: {
      type: "local",
    },
  })),
});`

This is my server option setup:

 `server: {
  process: {
    url: "/files/upload/",
    method: "POST",
    headers: {
      "X-CSRFToken": csrftoken,
    },
    withCredentials: false,
    onload: (response) => {
      console.log("triggered onLoad", images);
      const data = JSON.parse(response);
      images.push(data.id);
      return data.id;
    },
  },
  revert: (uniqueFileId, load, error) => {
    console.log("triggered revert", images);
    images = images.filter((x) => x !== uniqueFileId);
    load();
  },
  load: async (source, load, error, progress, abort, headers) => {
    console.log("triggered load", images);
    var myRequest = new Request(source);
    const response = await fetch(myRequest);
    const blob = await response.blob();
    load(blob);
  },
}`
fehmi commented 8 months ago

Great topic!