Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uploading File manually #24

Closed
Quadriphobs1 opened this issue Apr 5, 2018 · 39 comments
Closed

Uploading File manually #24

Quadriphobs1 opened this issue Apr 5, 2018 · 39 comments

Comments

@Quadriphobs1
Copy link

Is it possible to upload the file manually by letting the user click on a normal submit button alongside with a form either using ajax or direct post

@rikschennink
Copy link
Collaborator

rikschennink commented Apr 5, 2018

@Quadriphobs1 It's not possible to upload with direct post ( as you cannot assign files to a file input, this is where the File Encode plugin is useful ). You can call the processFiles method to start uploading files manually. Use the getFile method to retreive specific file items. You can then send those to the server manually.

edit in 2023:
You can now set the file input value in all major browsers, to do this with FilePond, set storeAsFile to true

This means that if you have a form with a file input and server side logic that handles the file(s) upload, you can add FilePond to you file input and you won't have to make changes on the server. No need for the file encode plugin.

@Quadriphobs1
Copy link
Author

Quadriphobs1 commented Apr 5, 2018

Okay, I seems to get that part but where am little confused is the processFiles method which requires query, what is the query structured required here like... I do hope you can help with that

@rikschennink
Copy link
Collaborator

@Quadriphobs1 Ah, tested, and indeed it didn't work when omitting arguments. Just released a fix version 1.2.9. You can now trigger uploading of all files by calling myPond.processFiles() without arguments.

@Quadriphobs1
Copy link
Author

Although I don't seem to get what you meant but what I am trying now is I created server in the setOptions which the process goes to a route but then I can't trace an error of why the upload is not working and there is no way to actually check for error with the option, or maybe I don't about it yet, maybe you can put me through that :)

@rikschennink
Copy link
Collaborator

If I understand correctly you want:

  1. User clicks button outside of FilePond, this starts the upload of all selected files
  2. A custom upload method is used to upload the files

Is that correct?

If so, can you describe which step is difficult and why?

@DamSenViet
Copy link

DamSenViet commented Apr 5, 2018

I need to submit a form and other fields along with the files in an AJAX post. Would it be possible to attach and add the base64 encoded data to my request?

What I'm aiming for is to submit both the file (base64 encoded) and other fields I need.
e.g. I want this object uploaded

{
    username: '*****',
    password: '*****',
    imgdata: '<base64 encoded file as a string>' // or Object that filePond is attempting to send
}

If I'm making the right assumptions I would have to read in each file inside the instance manually.
I would base64 encode via the provided FileReader and attach the string to my post request, but that would mean filePond basically just acts as GUI and has no functional purpose. Is it possible to get the Object that filePond encode will send off?

I would still like to see the upload progress being updated on the filePond instance when I manually submit the form. Would this be possible?

@rikschennink
Copy link
Collaborator

@DamSenViet You can use the File Encode plugin to have FilePond encode the files as base64 data. You can then send it along with a normal form post ( not using AJAX ).

If you want to send data asynchronously you can use a FormData object to store all the values and files, this is what FilePond uses to send data to the server.

To add data to files you can use the setMetadata method on the file object, this data will be sent along with the file.

If you need to customize the request further you can set up a custom processing method, it provides hooks to control the FilePond interface ( progress indicators and errors/success state ).

@Quadriphobs1
Copy link
Author

So finally I got to upload a file and in my controller I return the generated ID for the file but how would I add the return key to an hidden input and since I would prefer using the file-encode-plugin, how can someone attach the file-encode to an input filed... am just lost a little bit on it

@rikschennink
Copy link
Collaborator

If you're using the File Encode plugin you don't need a process entry in the server configuration as you'll be uploading files on form submit ( note that this will cause trouble for large files ). When using the File Encode plugin the hidden inputs FilePond generates contain the file data.

@nifte
Copy link

nifte commented Apr 25, 2018

@rikschennink Could you provide an example of how to add the encoded files to a FormData object? I'm having trouble figuring it out.

@DamSenViet
Copy link

@nifte check out the add files before encode. The op dropped a codepen that checks on the element with the img data.

@nifte
Copy link

nifte commented Apr 25, 2018

@DamSenViet I'm not seeing that codepen anywhere... 😅 Also, I believe I'm trying to do exactly what you were trying to do. Did you figure out a way to add the files along with other form inputs to your FormData for an AJAX-based submit?

@DamSenViet
Copy link

Oh my bad, it was an issue and I was typing on my phone.

Here ya go:

#28

The issue's been fixed, but the codepen in the thread should show you how to extract the data.

@nifte
Copy link

nifte commented Apr 26, 2018

@DamSenViet So, I figured out how to access the Base64-encoded data for each file, but I'm still confused on how to actually attach them to a FormData object like @rikschennink mentioned above...

@DamSenViet
Copy link

@nifte C'mon man we're all developers but you gotta learn how to use the APIs.

https://developer.mozilla.org/en-US/docs/Web/API/FormData/append

Really not that hard to Google "formData".

@nifte
Copy link

nifte commented Apr 26, 2018

@DamSenViet I know how to use the FormData object. The part I'm confused on is what to actually append to the FormData (i.e. the 'value' parameter). What am I supposed to do with the JSON that Filepond gives me?

@DamSenViet
Copy link

@nifte well the file is base64 encoded. Get the base64 string via the data json and attach that to your FormData. Send that off then process the data server side (save/write in base64 mode, etc).

@nifte
Copy link

nifte commented Apr 27, 2018

@DamSenViet Okay, this is what I've got:

var form = new FormData();
for (let i = 0; i < $('.filepond--list input').length; i++) {
	let file = JSON.parse($('.filepond--list input').eq(i).val());
	form.append('file' + i, file.data);
}

I'm taking the data from each hidden input, and appending it to the FormData object. But when I check the $_POST object on my server, it just shows each file with the data as a string.

@DamSenViet
Copy link

DamSenViet commented Apr 27, 2018

That's exactly what a file is. It's literally just a giant string, usually in binary as 0's & 1's. If you open a file in binary reading mode that's literally all you will see. When you use base64 encoding it helps compress the binary representation.

e.g. Here's why we base64
15 in binary (base 2) is "1111" = 4 characters = 4 bytes
15 in hex (base 16) is "F" = 1 character = 1 byte
Imagine you have an img in binary that's millions of characters long. No server wants to handle that kind of load. We need to take the burden off the network since it can create bottlenecks.

You can either send a string that's either 4 million bytes you can send a string that's 1 million bytes. It's pretty obvious what you should be picking. As the file size gets bigger, the benefits get better (relatively). If you're wondering why we can't send it in binary directly, there's really nothing stopping you if you know how to manipulate AJAX dataType. It's just the browser does not let you just grab the file data on your own. It's prohibited as a security measure. That's why we use the FileReader object to get the base64 representation, because it's an open API (and currently the only method available to us).

That's also why we send the string off in base64 encoding. You take the string and write to a new file in base64 mode (turns base64 back into binary). If you can't write in base64 mode, decode the base64 string and write the resulting decoded string.

In whatever language you're using you need to decode base64 the file. Base64 is standard so I doubt you'll have trouble finding a library.

e.g. in a node.js server you would do something like this if you wanted to save the file somewhere:

var fs = require("fs");
fs.writeFile("out.png", base64String, 'base64', function(err) {
  console.log(err);
}

That would be the entire upload operation

  • send file to server as string, encoded in base64
  • have server save the file somewhere, decoded from base64 back to binary

If this sounds foreign to you, I can't help you.

@rikschennink
Copy link
Collaborator

@nifte If you're going to send FormData objects, why not use a custom process method instead of the File Encode plugin?

@nifte
Copy link

nifte commented Apr 27, 2018

@DamSenViet Thank you for the breakdown. I've never messed around with Base64, so I'll do some more research. I do understand the concept, though, from your explanation. I'm using PHP/Apache, as opposed to NodeJS, but I'm sure it works similarly.

@rikschennink I already have a php file that handles files submitted from my form. I'm basically just trying to use Filepond as the UI for the file inputs in my form, so I'll use whatever the easiest solution is.

@rikschennink
Copy link
Collaborator

rikschennink commented Apr 28, 2018

@nifte If you’re submitting async set the server property to your PHP file location. If you’re submitting a form ( page reloads ) then FormData is not going to help you (as it’s for use with fetch or XMLHttpRequest), you’ll need to adjust the backend code to accept encoded files ( see the PHP boilerplate for the required code changes ).

@GeSeRnnov
Copy link

@rikschennink Hello.
Could you help with my task, it similar to the tasks above. I need to submit form fields data (name, email...) + loaded files to the server. Can I use processFiles method in the handle submit function (when the user filled all fields and loaded files into server/api/tmp by <Filepond/> and pressed "Submit") and how to call it in React? I mean I don't have a link to Filepond:

import { FilePond, File, registerPlugin } from 'react-filepond';

handleSubmit(event){
	event.preventDefault();
		
	const pond =  ????
	pond.processFiles().then(files => {
		   // files have been processed
	});

	const data = new FormData();
	data.append('name', this.state.name)		
	data.append('files', this.state.files)
	...
	data.append( ... )


	 axios
	 	.post('/api/send.php', data, ...)
	 	.then(...)
	 	...
}

<form>
	<TextField.../>
	...
	<TextField.../>
	<Filepond ref={ref => this.pond = ref}
		allowMultiple={true}                       
		server="api/"
		oninit={() => this.handleInit() }					
		onupdatefiles={(fileItems) => {
			this.setState({
			  files: fileItems.map(fileItem => fileItem.file)
			});
	}}>
		{this.state.files.map(file => (
		<File key={file} src={file} origin="local" />
		))}
	</Filepond>
    <button type="submit" >Submit</button>
</form>

@rikschennink
Copy link
Collaborator

rikschennink commented Jan 15, 2019

@GeSeRnnov
You have a reference to FilePond, you set it here:

<Filepond ref={ref => this.pond = ref}>

this.pond will point to the FilePond instance.

I advise to let FilePond send the files to the server, then when you submit the form with Axios you only send the file IDs returned by the server. Now the server knows which files have been uploaded and can move the files to the right location/database.

If that's not what you want, then use this.pond.getFiles() and add the file objects (fileItem.file) to the data before sending everything in one go to the server with Axios.

@GeSeRnnov
Copy link

@rikschennink, your advise was helpful for me. All works now)).
Thank you very much.

@hooziewhatsit
Copy link

I advise to let FilePond send the files to the server, then when you submit the form with Axios you only send the file IDs returned by the server. Now the server knows which files have been uploaded and can move the files to the right location/database.

How exactly do to we get the list of IDs back from filepond? I have the load(id); saving them as part of the process: function, but I haven't been able to find any documentation on getting that list back out? Technically I can make my own array with the unique IDs, but using filepond seems cleaner...

I'm uploading multiple images to the server and saving them, then when they finish adding text on their post they hit 'Save'. At that point I want to send the post information, as well as the list of IDs corresponding to that post so the server can then do some stuff.

@rikschennink
Copy link
Collaborator

getFiles

@hungdev
Copy link

hungdev commented Mar 2, 2019

@rikschennink thanks you.

  async onUpload() {
    const { arrFiles } = this.state
    console.log('arrFiles', arrFiles)
    var data = new FormData();
    _.forEach(arrFiles, file => {
      data.append('ebookFile', file.file);
    })
    // data.append('hi', 'hung')
    try {
      const response = await uploadFiles(data)
      console.log('response', response)
    } catch (e) {
      console.log(e)
    }
  }

for those who come later.

@surfer77
Copy link

This was helpful for me for future people with this specific problem:
https://github.com/pqina/filepond-docs/blob/master/content/patterns/API/server.md

@siddmegadeth
Copy link

How to work using this kind of Data . I am getting this result as an Array . There could be 10 images.
I am using Cordova and there are no input here. all is done using a native media picker used in my Cordova app and post selection of images from this gallery picker i get the result as follow. No i want to use filepond to upload this data to my server which is written in NODEJS

> 
> {
> exifRotate: 0
> index: 0
> mediaType: "image"
> name: "Screenshot_20190702-023602.png"
> path: "/storage/emulated/0/Pictures/Screenshots/Screenshot_20190702-023602.png"
> quality: 100
> size: 1033217
> src: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD"
> thumbnailBase64: "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABALDA4MChAODQ4SER"
> uri: "file:///storage/emulated/0/Pictures/Screenshots/Screenshot_20190702-023602.png"
> __proto__: Object
> }
> 
> 
>  

Any Suggestions

@rikschennink
Copy link
Collaborator

@siddmegadeth In theory you should be able to add the path and FilePond will try to load the file from that location. You can do this with the addFile method.

If that doesn't work you can load the file object with FileReader and then pass it to FilePond.

@siddmegadeth
Copy link

If possible can you provide exmaple. I am having a hardtime going through filepond documentation.
All API is listed but just don't know from where to start and how to use, specific to my usecase. Mostly cover input type="file" .

@rikschennink
Copy link
Collaborator

rikschennink commented Jul 11, 2019

@siddmegadeth If you have a filePond instance with a server location.

const pond = FilePond.create({ server:'./api' });
pond.addFile('./path/to/file');

@siddmegadeth
Copy link

siddmegadeth commented Jul 12, 2019

How can i send Profile ID or any user identification . I am not able to send user unique ID so that i can query this user and create new file or else append this file if user is found. Right now i cannot send information which i can extract in req.body

Plus how do i trigger upload for above options

I am using Cordova-Native-Photo and this the format i receive
https://github.com/DmcSDK/cordova-plugin-mediaPicker

{index: 0
mediaType: "image"
name: "IMG_20190711_184619078.jpg"
path: "/storage/emulated/0/DCIM/Camera/IMG_20190711_184619078.jpg"
size: 5167613
uri: "file:///storage/emulated/0/DCIM/Camera/IMG_201907}

I am not able to add this to filePond using pond.addFile('./path/to/file');
Please suggest

@rikschennink
Copy link
Collaborator

@siddmegadeth please post questions to StackOverflow as described in the issue template. This is related to Cordova not FilePond.

@zyyoo
Copy link

zyyoo commented Jul 1, 2020

Is that easy to understand? FormData + getFiles

 html:
<input type="file" class="filepond" name="filepond" id="id_filepond" multiple data-max-file-size="3MB" data-max-files="3" /><button id ='test'>3232</button>
js:
           const pond = FilePond.create(document.querySelector('#id_filepond'), {
                labelIdle: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
            });
            $('#test').click(function () {
                const files = pond.getFiles()
                console.log(files)
                const params = new FormData();
                params.append('test', 'hahaha'); // Your custom data
                for ( var i in files) {
                    params.append('file', files[i].file);
                }
                $.ajax({
                    url: "xxxxxxxx",
                    type: "POST",
                    processData: false,
                    contentType: false,
                    data: params,
                    success: function (d) {
                    }
                });
            })

@JonathanSchndr
Copy link

JonathanSchndr commented Oct 2, 2020

This is my solution, inspired by @zyyoo

HTML
<input type="file" id="data" name="data" multiple>

Create FilePond
let filesObj = FilePond.create(document.getElementById("data"), {});

Collect Form
let formData = new FormData($("XX")[0]);
formData.delete("data"); //data is the name of the orignal input file; import to delete
  $.each(filesObj.getFiles(), function (i, file) { //filesObj is the instance of FilePond.create()
  formData.append('file-' + i, file.file);
});

Submit Form
$.ajax({
  url: "XX",
  method: "POST",
  data: formData,
  cache: false,
  processData: false,
  contentType: false
}).done((data) => {});

@PPHelios
Copy link

@GeSeRnnov You have a reference to FilePond, you set it here:

<Filepond ref={ref => this.pond = ref}>

this.pond will point to the FilePond instance.

I advise to let FilePond send the files to the server, then when you submit the form with Axios you only send the file IDs returned by the server. Now the server knows which files have been uploaded and can move the files to the right location/database.

If that's not what you want, then use this.pond.getFiles() and add the file objects (fileItem.file) to the data before sending everything in one go to the server with Axios.

@GeSeRnnov You have a reference to FilePond, you set it here:

<Filepond ref={ref => this.pond = ref}>

this.pond will point to the FilePond instance.

I advise to let FilePond send the files to the server, then when you submit the form with Axios you only send the file IDs returned by the server. Now the server knows which files have been uploaded and can move the files to the right location/database.

If that's not what you want, then use this.pond.getFiles() and add the file objects (fileItem.file) to the data before sending everything in one go to the server with Axios.

thanks for this great project and sorry for reopening this issue,
I'm trying to upload files manually and managed to make it work, but the uploaded files are the unprocessed ones (without the watermark) which is visible in the preview,

the FilePond component :

<FilePond
ref={ref}
files={imageFiles}
onupdatefiles={setImageFiles}
allowMultiple={true}
maxFiles={15}
allowReorder
dropValidation
name="files" /* sets the file input name, it's filepond by default /
labelIdle='Drag & Drop your files or Browse'
//FileTypeValidation plugin
allowFileTypeValidation
labelFileTypeNotAllowed="File of invalid type"
imagePreviewMaxFileSize="6MB"
acceptedFileTypes={["image/
"]}
//FileSizeValidation plugin

allowFileSizeValidation
minFileSize="100KB"
maxFileSize="6MB"
labelMaxFileSizeExceeded="File is too large"
labelMaxFileSize="Maximum file size is {filesize}"
//
allowFileMetadata
//
allowImageTransform
imageTransformClientTransforms
imageTransformCanvasMemoryLimit

fileMetadataObject={{
markup: [
[
"rect",
{
left: 0,
right: 0,
bottom: 0,
height: "100px",
backgroundColor: "rgba(0,0,0,.5)",
},
],
[
"image",
{
right: "10px",
top: "10px",
width: "60px",
height: "60px",
src: logo,
fit: "contain",
},
],
],

onpreparefile: (file, output) => {
console.log(output);

},
}}

     imageTransformBeforeCreateBlob={(canvas) =>
       new Promise((resolve) => {
         // Do something with the canvas, like drawing some text on it
         const ctx = canvas.getContext("2d");
         ctx.font = "48px serif";
         ctx.fillText("Bdoon Wasyt", 10, 50);

         console.log("imageTransformBeforeCreateBlob", ctx, canvas);

         // return canvas to the plugin for further processing
         resolve(canvas);
         imgy = canvas
       })
     }
     imageTransformAfterCreateBlob={(blob) =>
       new Promise((resolve) => {
         // do something with the blob, for instance send it to a custom compression alogrithm
         console.log("imageTransformAfterCreateBlob", blob);


         // return the blob to the plugin for further processing
         resolve(blob);
       })
     }

/>

in the upload function i access the files using:

      let file = await ref.current.getFile(i).file

also imageTransformBeforeCreateBlob doesn't add text

i appreciate help fixing this.

@IlyasMohetna
Copy link

IlyasMohetna commented Dec 25, 2023

While this question might be a bit dated, here's a response for individuals currently encountering this issue.

I don't know why I saw a lot of people saying that this is not possible. There is a workaround without limitations. If you have data, you just want to put it somewhere else.

Solution :

  1. In the form you want to submit create an input

    • If it's multiple make sure you put the brackets for the name

      <input type="file" id="files" name="files[]" multiple>
      
    • If it's not multiple

      <input type="file" id="files" name="files">
      
  2. Create your pond instance

    const pond = FilePond.create(element);
    
  3. Attach an event and call a function

    pond.on('addfile', (error, file) => {
     PutIntoInput();
    }
    
  4. Create the function

    function PutIntoInput(){
        const filesFromPond = pond.getFiles(); // pond is your instance
        const filesInput = $('#files')[0]; // element we created in step1
        const newFileList = new DataTransfer(); // new file list
        filesFromPond.forEach(file => { // Add each file to a list
            newFileList.items.add(file.file);
        });
        filesInput.files = newFileList.files; // Set the file list
    }
    

PS : You might use CSS to hide the input type="file" because you cannot set it to hidden in this case.

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

No branches or pull requests