I am making a user profile page with an image avatar.
The code works perfectly until the user re-enters the profile page; in that case, nothing happens when the user clicks on the profile image.
It should remove the image on the first click, and then he should be able to upload a different image.
I store the image as a base64 string.
Code I use to set preview image:
const [image, setImage] = useState(null);
const [preview, setPreview] = useState(null);
useEffect(()=> {
if(image){
const reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result);
}
reader.readAsDataURL(image);
}else{
setPreview(null);
}
}, [image]);
Code I use to set preview form DB if it exists:
if(userData[11] != ''){
setImage(null);
setPreview(userData[11]);
}
And finally, in return of component:
{preview ? (<img class="image-preview" onClick={() => {setImage(null)}} src={preview} />) :(
<div class="image-upload">
<label for="file-input">
<img src="https://icons.iconarchive.com/icons/bokehlicia/captiva/128/multimedia-photo-manager-icon.png"/>
</label>
<input accept="image/*" onChange ={(e) =>{
const file = e.target.files[0];
if(file && file.type.substring(0, 5) === "image"){
setImage(file);
} else{setImage(null);}
}} id="file-input" type="file" />
</div>)}
onClick event in tag causes me trouble.
Related
How to preview selected image in react js? this is my code.
I am new to react.js and I still have no idea how to call functions or like this.
const HomepagePage = (props) => {
const hiddenFileInput = React.useRef(null);
const handleClick = event => {
hiddenFileInput.current.click();
};
const handleChange = event => {
const fileUploaded = event.target.files[0];
props.handleFile(fileUploaded);
};
return (
<>
<Button
className="common-pointer font-bold lg:ml-[44px] xl:ml-[56px] 2xl:ml-[63px] 3xl:ml-[75px] lg:text-[18px] xl:text-[23px] 2xl:text-[25px] 3xl:text-[31px] text-center tracking-ls1 w-[63%]"
onClick={handleClick}
shape="RoundedBorder5"
>
Upload Image
</Button>
<input type="file"
ref={hiddenFileInput}
onChange={handleChange}
style={{display:'none'}}
/>
<Img
src="images/img_11.png"
className="absolute lg:h-[382px] xl:h-[478px] 2xl:h-[537px] 3xl:h-[645px] w-[100%]"
alt="Eleven"
/>
The image selected from the button should replace the image 11. Any idea how to do this?
I have a Collection Type called events.
events has a name and image in its data architecture.
Therefore events has a name field and a image field.
I have managed to upload a file to strapi v4 via the /api/upload endpoint.
I know the upload is working because the file being uploaded does appear in the strapi localhost:1337 back end admin area and it also appears in the cloudinary backend.
However, the image file does not end up being added to the image field of the event.
I have tried to follow the code of multiple examples online but it seems like most of the examples online are for v3 and and v4 of strapi.
In any case below is my code where I do add in the ref, refId, and field of the formData before uploading the file...but it still does not work.
export default function ImageUpload({ evtId, imageUploaded }) {
const [image, setImage] = useState(null)
const handleSubmit = async (e) => {
console.log('handleSubmit')
e.preventDefault()
const formData = new FormData() // pure javascript nothing to do with react
formData.append('files', image)
formData.append('ref', 'events') //'ref' The collection we want to use
formData.append('refId', evtId) //'refId' The event Id
formData.append('field', 'image') //'field' the image field we called 'image'
const res = await fetch(`${API_URL}/api/upload`, {
method: 'POST',
body: formData,
})
if (res.ok) {
console.log('res.ok')
// 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 className={styles.form}>
<h1> Upload Event Image</h1>
<form onSubmit={handleSubmit}>
<div className={styles.file}>
<input type='file' onChange={handleFileChange} />
</div>
<input type='submit' value='Upload' className='btn' />
</form>
</div>
)
}
What am I doing wrong?
What should I do so that the newly uploaded file would be added to the image field of the event entry of event Collection Type??
Changed the line:
formData.append('ref', 'events')
to
formData.append('ref', 'api::event.event')
and it worked...
Below is updated code...hope it helps other people...
import React from 'react'
import { useState } from 'react'
import { API_URL } from '#/config/index'
import styles from '#/styles/Form.module.css'
export default function ImageUpload({ evtId, imageUploaded }) {
const [image, setImage] = useState(null)
const handleSubmit = async (e) => {
console.log('handleSubmit')
e.preventDefault()
const formData = new FormData() // pure javascript nothing to do with react
formData.append('files', image)
// formData.append('ref', 'events') //'ref' The collection we want to use
formData.append('ref', 'api::event.event')
formData.append('refId', evtId) //'refId' The event Id
formData.append('field', 'image') //'field' the image field we called 'image'
const res = await fetch(`${API_URL}/api/upload`, {
method: 'POST',
body: formData,
})
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 className={styles.form}>
<h1> Upload Event Image</h1>
<form onSubmit={handleSubmit}>
<div className={styles.file}>
<input type='file' onChange={handleFileChange} />
</div>
<input type='submit' value='Upload' className='btn' />
</form>
</div>
)
}
I made vid that explains it
https://www.youtube.com/watch?v=54_SKMmrJkA
Basically you have to upload files in a specific format or else it will not work
Great answer but can't use this to update the image field in the event collection even though it successfully uploads to the media
Please review my code first.
const test = () => {
const [files, setFiles] = useState ([]);
//I think I have to edit following statement.
const handleFile = (e) => {
const newFiles = []
for (let i=0; i < e.target.files.length; i++) {
newFiles.push(e.target.files[i])
}
setFiles(newFiles)
};
return (
{files.map((file, index) => (
<div>
<div key={index}>
<p>
{file.name}
</p>
<Button size='small' onClick={() => {deleteSelectedFile(file.name)}}>
Delete
</Button>
</div>
</div>
))}
<div>
<label onChange={handleFile}>
<input type='file' multiple />+ Attach File
</label>
</div>
)
}
with handleFile statement, I can appropriately get the files.
However, when I upload one file at a time and then upload one file again,
the file is not added. the file replaces file.
There is not problem when I upload multiple time at once.
For example, I upload 'hello.jpg', and it renders well in the screen. Then, I upload 'goodbye.jpg', it renders well, but 'goodbye.jpg' replaces 'hello.jpg'.
Therefore, what I see is just 'goodbye.jpg' [button], not
'hello.jpg' [button]
'goodbye.jpg' [button]
.
I want my files to stacked up, without replacing.
I need some wisdom!
In my opinion, you only need to spread the prev state values and the files during the change event.
import { useState } from "react";
export default function App() {
const [files, setFiles] = useState([]);
const handleChange = (e) => {
// This is what you need
setFiles((prev) => [...prev, ...Object.values(e.target.files)]);
};
return (
<div>
<label onChange={handleChange}>
<input type="file" multiple />
</label>
{files.map((file) => {
return <p>{file.name}</p>;
})}
</div>
);
}
how about you don't create a new variable for new files, you just set the state for the files since it's an array
setFiles(oldFile => [...oldFile,e.target.files[i]]);
If it's possible you can drop a codepen link
i am creating an ecommerce website using NextJs. i want to give admin rights where admin can upload an product image which will be displayed later on dashboard along with the product.
My question is how to achieve this?? i can store the image location in db along with other product details but what about image?? where to store this uplaoded image so that it can be automatically displayed on page load.
one way would be to load images in file system where app is served but then i would have to deploy app again and again and this seems impractical. Also i dont think there is way to directly load images to public folder.
Looking forward to answers.
thanks
You basically do it like you would do it in React. Create a component which handles the displaying of the preview as well as the upload to an external server. I created a codepen for you to test the component in the wild. It consists of this:
import React from "react";
const ImageUpload = props => {
const [currentFile, setFile] = React.useState();
const [previewImage, setPreview] = React.useState();
const [success, setSuccess] = React.useState(false);
const selectFile = function (e) {
setFile(e.target.files[0]);
let reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result);
};
reader.readAsDataURL(e.target.files[0]);
};
const submit = function () {
let fd = new FormData();
fd.append("file", currentFile);
let request = new XMLHttpRequest();
request.onreadystatechange = function (state) {
if (
state.originalTarget.readyState === 4 &&
state.originalTarget.status === 200
) {
setSuccess(true);
}
};
request.open(
"POST",
"https://us-central1-tutorial-e6ea7.cloudfunctions.net/fileUpload",
true
);
request.send(fd);
};
return (
<div>
<h1>Upload an image</h1>
<input type="file" accept="image/*" onChange={selectFile} />
{previewImage && !success && (
<div>
<img className="preview" src={previewImage} alt="" />
</div>
)}
{success && <div>Image successfully uploaded</div>}
<button onClick={submit}>Upload</button>
</div>
);
};
export default ImageUpload;
An <img/> element which accepts files and renders a preview in an onChange event using the FileReader api.
A submit function which uses the FormData interface to append the image and uses XMLHttpRequest to upload the file to the server.
Some simple UI logic to display the preview to the user.
Check out this tutorial for a more detailed explanation.
I'm building a resume uploader form and I'd like to show the uploaded files name after it get's uploaded. I have an onChange handler for when the uploaded file is changed, but when I try to read the event's properties, specifically target as that's where I read my infor should be, it comes back as null.
This is my file input uploader:
<input
id="upload-resume"
className="update-profile__upload"
type="file"
onChange={handleFileUpload}
/>
And this is my handler:
const handleFileUpload = file => {
console.log("This is the file");
console.log(file);
};
To access all the file properties.
const [filesState, setFilesState] = React.useState([]);
return (
<>
<input
type="file"
name="file-upload"
onChange={e => {
setFilesState(e.target.files);
}}
/>
<br />
{Array.from(filesState).map((file, index) => {
return (
<div key={index}>
<p>Name: {file.name}</p>
<p>Type: {file.type}</p>
<p>Size: {Number(file.size / 1000).toFixed(2)} KB</p>
</div>
);
})}
</>
);
this works.
const handleFileUpload = file => {
console.log("This is the file");
console.log(file.target.files[0]);
};
refer here for more info on uploading file. upload file
The uploaded file is in the files array of the target.
const handleFileUpload = file => {
console.log("This is the file");
// array of files with the following properties
// name, type, lastModified , size
console.log(file.target.files);
};