How to multiple image upload with React.js to Firebase - javascript

using react js I need multiple image upload to firebase I tried with below code is not working to multiple upload.
//display multi
handleChange(event) {
const file = Array.from(event.target.files);
this.setState({ file });
}
//upload multi
fileuploadHandler = () => {
const storageRef = fire.storage().ref();
storageRef.child(`images/${this.state.file.name}`)
.putFile(this.state.file).then((snapshot) => {
});
}
render() {
return (
<div className="App">
<input id="file" type="file" onChange={this.handleChange.bind(this)} required multiple />
<button onClick={this.fileuploadHandler}>Upload!</button>
</div>
)
}

To handle multiple files, you'll need to loop over the files property of the input.
So:
const storageRef = fire.storage().ref();
this.state.file.forEach((file) => {
storageRef
.child(`images/${file.name}`)
.putFile(file).then((snapshot) => {
})
});

Related

Link upload image with content with strapi api in reactjs

I try to use strapi for the first time with react and I can't understand how I can link upload (in strapi) image to my content, I know how upload, I know how post something but I don't know how link this. I readed a lot of times strapi documentation but I can't understand.
My code
function ProductCreateApi({ evtId }) {
const [image, setImage] = useState(null)
const [posts, setPosts] = useState([])
const [updatesData, setUpdatesData] = useState({
titleproductgroup: "",
})
function updateEdit(e) {
const newupdate = { ...updatesData }
newupdate[e.target.id] = e.target.value
setUpdatesData(newupdate)
console.log(newupdate)
}
const handleSubmit = async (e) => {
console.log('handleSubmit')
e.preventDefault()
const formData = new FormData()
formData.append('files', image) // the pic
formData.append('ref', 'api::product-group.product-group') // link with my table
formData.append('refId', evtId)
formData.append('field', 'picproductgroup') // the row
axios.post('http://localhost:1337/api/upload/', formData)
e.preventDefault()
const res = axios.post(`http://localhost:1337/api/product-groups/`, {
"data": {
titleproductgroup: updatesData.titleproductgroup
}
})
if (res.ok) {
console.log('res.ok')
console.log('res', res)
// imageUploaded()
}
}
const handleFileChange = (e) => {
console.log('handleFileChange')
console.log(e.target.files[0]) //this will give us an array and we want the first wone so we add 0
setImage(e.target.files[0])
}
return (
<div>
<h1> Upload Event Image</h1>
<form onSubmit={handleSubmit}>
<input onChange={(e) => updateEdit(e)} id="titleproductgroup" value={updatesData.titleproductgroup} type="text" placeholder={posts.titleproductgroup} />
<div>
<input type='file' onChange={handleFileChange} />
</div>
<input type='submit' value='Upload' className='btn' />
</form>
</div>
)
}
export default ProductCreateApi
In the comment I wrote what I understand from attributes
and here my "table"
Thanks for your help. I hope I can improve myself thanks to you
I find solution, I just change that
const handleSubmit = async (e) => {
console.log('handleSubmit')
e.preventDefault()
const formData = new FormData()
formData.append('files', image) // the pic
formData.append('ref', 'api::product-group.product-group') // link with my table
formData.append('refId', evtId)
//formData.append('field', 'picproductgroup') // the row
axios.post('http://localhost:1337/api/upload/', formData).then(res => {
console.log(res.data[0].id);
const res2 = axios.post(`http://localhost:1337/api/product-groups/`, {
"data": {
titleproductgroup: updatesData.titleproductgroup,
picproductgroup: res.data[0].id,
}
})
if (res2.ok) {
console.log('res.ok')
console.log('res', res2)
// imageUploaded()
}
}).catch(error => {
console.log(error.message);
});
//e.preventDefault()
}
const handleFileChange = (e) => {
console.log('handleFileChange')
console.log(e.target.files[0]) //this will give us an array and we want the first wone so we add 0
setImage(e.target.files[0])
}
return (

handle state for uploading multiple upload react

i want to add data after uploading 1 image
const [file, setFile] = useState(null);
const handleUpload = (e) => {
setFile(e.target.files);
};
<input
type="file"
onChange={(e) => handleUpload(e)}
ref={fileInputRef}
multiple
/>
this was work if i select 2 or more files at once.
however i want to handle after choosing 1 image. user will be upload using the same input.
i have tried using method below and created error TypeError: file is not iterable
const handleUpload = (e) => {
setFile([...files, e.target.files]);
};
or
const handleUpload = (e) => {
let filesArray = file;
if (file) {
for (var i = 0; i < file.length; i++) {
filesArray.push(e.target.files[i]);
}
}
setFile(filesArray);
};
do you guys have any solution?
You should first set the default value for file as an array in your useState, then while using the set method you need to use the spread (...) operator properly. This will resolve your error TypeError: file is not iterable
Below are the changes that you will need to perform.
export default function InputComponent() {
const [file, setFile] = React.useState([]);
const handleUpload = (e) => {
setFile([...file, ...e.target.files]);
};
return (
<div>
<input type="file" onChange={(e) => handleUpload(e)} multiple /><br/><br/>
<textarea value={file}/>
</div>
);
}

SetState not rendering the component

So I am working on my React app and a one point i need to upload some files. So I simply used the input file to make it work. I set its display none as I wanted my attachment icon to be clicked when wanting to upload the file.
Problem : Using the ref method, everything is working fine except one thing and that is below in my hangleFileChange function, when the setFiles() set the file variable, the component is not rendered and I do not see the file array. but if I do the file saving simply like
setFile(event.target.files[0])
I can see the rendering . But with the below code, the component is not rendering
import React, { useRef, useState } from "react";
const App = () => {
const fileInput = useRef(null);
const [file, setFile] = useState([]);
const handleClick = () => {
fileInput.current.click();
};
const handleFileChange = (event) => {
console.log("Make something");
let newFiles = file;
newFiles.push(event.target.files[0]);
console.log(newFiles);
setFile(newFiles);
};
// This should run on every render
console.log("the files array is ", file);
return (
<div className="patientactions-container">
<input
type="file"
style={{ display: "none" }}
onChange={(e) => handleFileChange(e)}
ref={fileInput}
/>
<div onClick={() => handleClick()}>clck</div>
</div>
);
};
export default App;
Please help.
Sandbox : https://codesandbox.io/s/kind-breeze-czc3w?file=/src/App.js:0-692
Try this version
const handleFileChange = (event) => {
console.log("Make something");
// Set the ne variable to an array, not file
let ne = [];
ne.push(event.target.files[0]);
// then set it equals file.
ne = file;
console.log(ne);
console.log(file);
setFile(file);
};
You can fix the code like this below.
import React, { useRef, useState } from "react";
const App = () => {
const fileInput = useRef(null);
const [file, setFile] = useState(null);
const handleClick = () => {
fileInput.current.click();
};
const handleFileChange = (nfile) => {
console.log("Make something");
if (file == null) setFile([nfile]);
else setFile([...file, nfile]);
};
console.log("the files array", file);
return (
<div className="patientactions-container">
<input
type="file"
style={{ display: "none" }}
onChange={(e) => handleFileChange(e.target.files[0])}
ref={fileInput}
/>
<div onClick={() => handleClick()}>clck</div>
</div>
);
};
export default App;
I'd have put this in the comments but my rep is not high enough.
I had a problem with rendering changes to an array, because arrays use pointers it did not "register" a state change that was enough to cause a render. Using the spread operator in your solution affected the pointer and thus a render occurred.
In my own solution I set my array to null before adding content and that worked fine for my problem.

Allow uses to adjust the position of their profile pictures

I am building a website and want to include the feature that allows users to adjust the position of their profile picture when uploading (which part of the picture gets displayed by the "img" element). LinkedIn, for example, has this feature. I searched about how to implement the feature but did not find anything helpful. The code below is what I have right now: After the user selects a image file, it will be uploaded to firebase storage, then the web page will be re-rendered and the new image will be displayed on the web page. I am wondering whether anyone can give me a clue about how to add the feature to my existing code. Thanks!
Client-side code that lets users upload profile images
state = {
image: "",
edit: false
}
componentDidMount() {
const { profile } = this.props;
this.setState({
image: profile.image
})
}
......
handleUpload = (e) => {
e.preventDefault();
const image = e.target.files[0];
const { auth } = this.props;
this.props.uploadImage(image, auth.uid);
}
openFiles = (e) => {
e.preventDefault();
const input = document.getElementById("imageinput");
input.click();
}
......
render() {
return (
......
<img src={this.state.image ? this.state.image : ditto}></img>
<input type="file" id="imageinput" hidden="hidden" onChange={this.handleUpload}></input>
<button onClick={this.openFiles}>Upload Profile Image</button>
......
Redux uploadImage action object
export const uploadImage = ( image, userid ) => (dispatch) => {
firebase.storage().ref('images/'+userid).put(image)
.then(() => {
return firebase.storage().ref(`images/`+userid).getDownloadURL()
})
.then((image) => {
firebase.firestore().collection("users").doc(userid).update({
image: image
})
}).then(() => {
dispatch({ type: EDIT_SUCCESS });
})
}

File Input doesn't store file information, just the name

I'm using redux-form#8.1.0 and redux#4.0.1 and saving the data in a MongoDB collection. However, when I watch the file object that I uploaded in my Mongo DBs' collection it just retrieves the name of the file.
FileInput.js is the component that I pass to the redux-form Field component
FileInput.js
import React from 'react';
const handleChange = (handler) => ({target: {files}}) =>
handler(files.length ? {file: files[0], name: files[0].name} : {});
export default ({
input: {onChange, onBlur, value: omitValue, ...inputProps},
meta: omitMeta,
...props
}) => (
<input type="file"
onChange={handleChange(onChange)} onBlur={handleChange(onBlur)}
{...inputProps} {...props} />
);
And this is how I use it in my form
...
import FileInput from './FileInput';
...
<Field name="fileUploaded" component={FileInput} type="file"
/>
And this is the document in the MongoDB collection
{...
"fileUploaded":{"name":"testingfile.png"},
...}
It seems it stores only the name of the file and I expect another key value pair with the file information/object in order to load and display this image/file later.
Redux-Form stores the file, perhaps you need to read it out and then send it as a multipart/form-data. The data should be accessible at state.form.myFormNameHere.values.mFieldNameHere.
I made an ImageDisplay component that may be of help. It reads the file from a red-form file input and displays a preview.
const ImageReader = ({ file }) => {
const reader = new FileReader();
const [imageUrl, setImageUrl] = useState('');
if (file && file.file instanceof Blob) {
reader.onload = (event) => {
const { target: { result } } = event;
setImageUrl(result);
};
reader.readAsDataURL(file.file);
return <Image src={imageUrl} />;
}
return <Image src={null} />;
};
ImageReader.defaultProps = {
file: null,
};
ImageReader.propTypes = {
file: PropTypes.shape({
name: PropTypes.string,
file: PropTypes.any,
}),
};

Categories