please I'm lost how can I upload multiple files
This is how I upload single files:
<div class="a-row a-spacing-top-medium">
<label class="choosefile-button">
<i class="fal fa-plus"></i>
<input
type="file"
#change="onFileSelected"
ref="files"
/>
<p style="margin-top: -70px">{{ fileName }}</p>
</label>
</div>
this is my script tag for image upload:
<script>
import axios from 'axios'
export default {
data() {
return {
selectedFile: null,
fileName: '',
photos: null
}
},
methods: {
onFileSelected(event) {
this.selectedFile = event.target.files[0]
console.log(this.selectedFile)
this.fileName = event.target.files[0].name
},
async onAddProduct() {
let data = new FormData()
data.append('photos', this.selectedFile, this.selectedFile.name)
const response = await axios
.post('http://localhost:5000/api/products', data)
.then(() => {
console.log(response)
})
}
}
}
</script>
each time I add multiple to my input tag it just uploads an image in my browser.
Please how can I go about multiple uploads?
Here's a basic blog post on how to upload a files to S3 in Vue through a node backend. This may help you out.
Basically what you need to do is create a backend that handles the files and uploads them. This can be done using multer, multer-s3 and node.
One thing that you should also change is just having
data.append('photos', this.selectedFile)
data.append('fileName', this.selectedFile.name)
Related
I was trying to upload an image using Angular to a google storage bucket. And everything is working fine with Postman.
But I'm stuck with angular typescript. Can anyone suggest to me a way to do this?
.html file
<input type="file" accept="image/png, image/jpeg" class="form-control upload-btn" formControlName="imageUpload" placeholder="Upload Images" (change)="uploadImage($event)" required>
.ts file
uploadImage(event: any) {
if (event.target.files && event.target.files[0]) {
const uploadImage=event.target.files[0];
const fileObject = {
userId: this.userId,
bucketName: 'Test123',
image: uploadImage
};
this.userService.uploadImage(fileObject).subscribe(data=>{
},err=>{
console.log("error occured")
}
)
}
}
.service file
uploadImage(fileObject: any){
return this.http.post('http://localhost:1337' + 'upload-image' , fileObject);
}
No any error occurs on the backend side. It worked fine with Postman.
Im not sure about the .ts file.
As suggested by #PrasenjeetSymon using FormData will help to upload images in Angular.
Here is the similar thread which demonstrate how to use FormData
You can use the tag from HTML:
<input type="file" name="file" id="file" (change)="onFileChanged($event)" />
and in the component:
public files: any[];
contructor() { this.files = []; }
onFileChanged(event: any) {
this.files = event.target.files;
}
onUpload() {
const formData = new FormData();
for (const file of this.files) {
formData.append(name, file, file.name);
}
this.http.post('url', formData).subscribe(x => ....);
}
[checkout the code snippet, i have tried
Please checkout the code i tried to fetch the images from the s3 bucket. Fetching is accomplished but unable to preview the fetched image.
<FilePond
style = {{marginTop:'10px'}}
files={files}
allowMultiple={true}
allowReorder={true}
onupdatefiles={setFiles}
imagePreviewHeight = "125px"
server={{
load: (source, load, error, progress, abort, headers) => {
var myRequest = new Request(source);
fetch(myRequest).then(function(response) {
response.blob().then(function(myBlob) {
load(myBlob);
});
});
},
process: null
}}
labelIdle='Drag & Drop your files or <span class="filepond--label-action">Browse</span>'
/>
]1
I am trying to upload images to realtime firebase database. I made it with one images but I have no idea how to add multiple images.
This is my solution for one image.
<v-layout row>
<v-flex xs12 sm6 offset-sm3>
<!-- accept nam govori da uzme slike i nista vise-->
<v-btn raised #click="onPickFile">Upload image</v-btn>
<input
type="file"
style="display:none"
ref="fileInput"
accept="image/*"
#change="onFilePicked"/></v-flex
></v-layout>
In data I have this two: imgURL: "",
image: null
And this is a method:
onFilePicked(event) {
//files is list of imaages by puting files[0] we are taking just one
const files = event.target.files;
let filename = files[0].name;
if (filename.lastIndexOf(".") <= 0) {
return alert("Please add a valid file!");
}
const fileReader = new FileReader();
fileReader.addEventListener("load", () => {
this.imgURL = fileReader.result;
});
fileReader.readAsDataURL(files[0]);
this.image = files[0];
},
Although, this is not a firebase related question, but I try to help anyway:
First of all, you should add multiple to the input-tag, so you can select more than only one file there:
// CHANGE THIS:
<input type="file" style="display:none" ref="fileInput" accept="image/*" #change="onFilePicked"/>
// TO THIS:
<input type="file" style="display:none" ref="fileInput" accept="image/*" #change="onFilePicked" multiple/>
I assume you stumbled upon this wierd 'for-loop' for the files.. I had the same issue and figured out when I type of instead of in, then I get the file itself, not just the index and there is no error.
I splitted up the main parts of your function and converted them in asyncron Promises (because there might be a timing error with the addEventListener)
This is just the idea of the multiple files upload. Maybe you should add some more error-catcher:
new Vue({
data: {
blobs: [],
images: [],
},
methods: {
async onFilePicked(event) {
const files = event.target.files
this.images =[]
this.blobs =[]
for (let file of files) {
this.images.push(file)
let blob = await this.prepareImagesForUpload(file)
this.blobs.push(blob)
}
this.uploadImagesToFirebase()
},
prepareImagesForUpload(file) {
return new Promise((resolve, reject) => {
let filename = file.name
if (filename.lastIndexOf(".") <= 0) {
alert("Please add a valid file: ", filename)
reject()
}
const fileReader = new FileReader()
fileReader.readAsDataURL(file)
fileReader.addEventListener("load", async () => {resolve(fileReader.result)})
})
},
uploadImagesToFirebase() {
//... do the firebase upload magic with:
console.log(this.blobs)
//...
}
}
})
Im trying to upload a file with React and see its contents, but what it gives me is C:\fakepath\. I know why it gives fakepath, but what is the correct way to upload and read the contents of a file in react?
<input type="file"
name="myFile"
onChange={this.handleChange} />
handleChange: function(e) {
switch (e.target.name) {
case 'myFile':
const data = new FormData();
data.append('file', e.target.value);
console.log(data);
default:
console.error('Error in handleChange()'); break;
}
},
To get the file info you want to use event.target.files which is an array of selected files. Each one of these can be easily uploaded via a FormData object. See below snippet for example:
class FileInput extends React.Component {
constructor(props) {
super(props)
this.uploadFile = this.uploadFile.bind(this);
}
uploadFile(event) {
let file = event.target.files[0];
console.log(file);
if (file) {
let data = new FormData();
data.append('file', file);
// axios.post('/files', data)...
}
}
render() {
return <span>
<input type="file"
name="myFile"
onChange={this.uploadFile} />
</span>
}
}
ReactDOM.render(<FileInput />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<div id="root"></div>
You may want to look into FileReader which can help if you want to handle the file on the client side, for example to display an image.
https://developer.mozilla.org/en-US/docs/Web/API/FileReader
You can use React Dropzone Uploader, which gives you file previews (including image thumbnails) out of the box, and also handles uploads for you.
In your onChangeStatus prop you can react to the file's meta data and the file itself, which means you can do any kind of client-side processing you want before or after uploading the file.
import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'
const Uploader = () => {
return (
<Dropzone
getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
accept="image/*,audio/*,video/*"
/>
)
}
Uploads have progress indicators, and they can be cancelled or restarted. The UI is fully customizable.
Full disclosure: I wrote this library.
Try to use Multer and gridfs-storage on the back end and store the fileID along with your mongoose schema.
// Create a storage object with a given configuration
const storage = require('multer-gridfs-storage')({
url: 'MONGOP DB ATLAS URL'
});
// Set multer storage engine to the newly created object
const upload = multer({ storage }).single('file');
router.post('/', upload, (req, res) => {
const newreminder = new Reminders({
category: req.body.category,
name:req.body.name,
type: req.body.type,
exdate: req.body.exdate,
location:req.body.location,
notes:req.body.notes,
fileID: req.file.id
});
newreminder.save(function(err){
if(err){
console.log(err);
return;
}
res.json({ "success": "true"});
});
});
Then on the front end treat it normally (with Axios) and upload the entire file and grab a hold of all the info in the normal react way:
onSubmit = (e) => {
e.preventDefault;
const formData = new FormData();
formData.append({ [e.target.name]: e.target.value })
formData.append('file', e.target.files[0]);
axios.post({
method:'POST',
url:'EXPRESS JS POST REQUEST PATH',
data: formData,
config:{ headers: {'Content-Type':'multipart/form-data, boundary=${form._boundary}'}}
})
.then(res => console.log(res))
.catch(err => console.log('Error', err))
}
Have you use dropzone ?
see this react-dropzone
easy implement, upload and return url if this important.
onDrop: acceptedFiles => {
const req = request.post('/upload');
acceptedFiles.forEach(file => {
req.attach(file.name, file);
});
req.end(callback);
}
You can use FileReader onload methods to read the file data and then can send it to the server.
You can find this useful to handle files using File Reader in React ReactJS File Reader
To add to the other answers here, especially for anyone new to React, it is useful to understand that react handles forms a little differently than people may be used to.
At a high level, react recommends using 'Controlled components" :
In most cases, we recommend using controlled components to implement forms. In a controlled component, form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself.
This essentially means that the user input, e.g. a text field, is also a state of the component and as the user updates it the state is updated and the value of the state if displayed in the form. This means the state and the form data are always in synch.
For an input type of file this will not work because the file input value is read-only. Therefore, a controlled component cannot be used and an 'uncontrolled component' is used instead.
In React, an is always an uncontrolled component because its value can only be set by a user, and not programmatically.
The recommended way to input a file type (at the time of writing) is below, from the react documentation here https://reactjs.org/docs/uncontrolled-components.html#the-file-input-tag:
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef();
}
handleSubmit(event) {
event.preventDefault();
alert(
`Selected file - ${this.fileInput.current.files[0].name}`
);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById('root')
);
The documentation includes a codepen example which can be built on.
When I want to upload an image and send the other data using FormData. Axios seems to serialize the image. Therefore, when i upload the image using Axios, the image is inside the body's payload as a string. As a result, I'm unable to use Multer on the server side to retrieve the uploaded image from the request.
This is my Vue code:
export default () {
name: 'app',
data () {
image: ''
},
methods: {
onFileChange (e) {
var files = e.target.files || e.dataTransfer.files
if (!files.length) {
return
}
// console.log(files[0])
// var x = files[0]
return this.createImage(files[0])
// return new Buffer(x)
},
createImage (file) {
// var image = new Image()
var reader = new FileReader()
var vm = this
reader.onload = (e) => {
// vm.image = e.target.result
vm.image = file.toString('base64')
console.log(vm.image)
}
reader.readAsDataURL(file)
},
submitStaff () {
const formData = new FormData()
formData.append('file', this.image)
formData.append('name', this.data.name)
formData.append('username', this.data.username)
formData.append('password', this.data.password)
axios.post('api/myApiUrl', formData)
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})
}
}
<input type="file" #change="onFileChange">
Request Payload (Error with Vue)
Request Payload (Successful with Postman)
How do i fix this? Thank you!
I faced a problem related to it and in my case I was setting Content-Type as a default configuration for all my requests, doing this:
axios.defaults.headers.common['Content-Type'] = 'application/json [or something]';
And, as I remember, part of my solution was to remove this configuration to make the upload works. I just erased that line from my code and all requests worked well. As soon I removed it, I could notice that my headers request changed to this (see attached image and notice the Content-Type entry):
Another thing you should be alert is the field name to your <input type="file" name="file">. I have a java backend expecting a parameter named as "file", so, in my case, my input file HAS to be set as "file" on my HTML and on my server side, like this:
public ResponseEntity<Show> create(
#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) { ... }
Observe the entry #RequestParam("file")...
And in the HTML file:
<form enctype="multipart/form-data" novalidate v-if="isInitial || isSaving">
<div class="well">
<div class="form-group">
<label>* Selecione o arquivo excel. O sistema fará o upload automaticamente!</label>
<div class="dropbox">
<input type="file" single name="file" :disabled="isSaving" #change="filesChange($event.target.name, $event.target.files); fileCount = $event.target.files.length"
accept="application/vnd.ms-excel" class="input-file">
<p v-if="isInitial">
Solte o arquivo excel aqui<br> ou clique para buscar.
</p>
<p v-if="isSaving">
Carregando arquivo...
</p>
</div>
</div>
</div>
</form>
You also can take a look at this tutorial, it my help you: https://scotch.io/tutorials/how-to-handle-file-uploads-in-vue-2
I hope it helps you!