Reputation: 363
I am trying to select multiple images, and the images are being selected and stored in the state, but only one image is displayed.Below is the code for the same
//Selecting the image and displaying the image
<div className="md-form mb-5">
<input type="file" id="form29" name='images' onChange={e => pickImage(e)} className="form-control validate" multiple hidden/>
<button className="btn btn-outline-dark btn-sm" onClick={e => selectImage(e)}>Pick Image</button>
</div>
<div className="row text-center">
{image.length > 0 ?
image.map(img => (
<div className="col-md-4" key={img.url}>
<img src={img.url} alt={img.name} className="img-fluid"/>
<span style={{cursor: 'pointer'}}>
<i class="far fa-trash-alt" onClick={e => deleteImage(img.name, e)}></i>
</span>
</div>
)) : <p>No Images Picked</p>}
</div>
//Defining the state
const [addDiary, setAddDiary] = useState({date: null, content: null, images: []});
const [ image, setImage ] = useState([]);
//Defining the methods to store and delete image
const selectImage = (e) => {
document.getElementById('form29').click();
}
const deleteImage = (name, e) => {
const remainingImage = image.filter(img => {return img.name !== name});
setImage(remainingImage);
const remainingImageState = addDiary.images.filter(img =>
{
return img.name !== name});
setAddDiary({...addDiary, images: remainingImageState });
}
const pickImage = (e) => {
console.log(e, 'e obj')
for(const file of e.target.files) {
const reader = new FileReader();
reader.onload = (e) => {
setImage([...image, {url: URL.createObjectURL(file), name: file.name}]);
console.log(e.target.name)
setAddDiary({ ...addDiary, images: [...addDiary.images, file]});
};
reader.readAsDataURL(file);
}
}
Upvotes: 1
Views: 1438
Reputation: 1652
The issue here is that you are updating the image each time is loaded, so you should first load all images into cache an finally update the state, you can do by putting this code
const pickImage = (e) => {
console.log(e, 'e obj');
const limitImages = e.target.files.length;
let count = 0;
const images = [];
for(const file of e.target.files) {
const reader = new FileReader();
reader.onload = (e) => {
images.push({ url: URL.createObjectURL(file), name: file.name });
count++;
if (count === limitImages) {
// here all images are loaded, so update the state
setImage(images);
setAddDiary({ ...addDiary, images: addDiary.images.concat(images)});
}
};
reader.readAsDataURL(file);
}
}
Remember you should handle the error event too, too notify the user that was an error
So you can avoid the selectImage
method to trigger onClick event into the input, just by adding an id
to your input file
and use a label to trigger the event, like this:
<div className="md-form mb-5">
<input type="file" id="form29" name='images' onChange={e => pickImage(e)} className="form-control validate" multiple hidden id="file-picker" />
<button className="btn btn-outline-dark btn-sm" onClick={e => selectImage(e)}>
<label id={'file-picker'}>
Pick Image
</label>
</button>
</div>
I hope it can help you
Upvotes: 1
Reputation: 2828
Your key for you map is set as an object. Try setting as the image name to avoid ommitting. React cannot tell the keys apart if they are objects:
<div className="col-md-4" key={img.name}>
<img src={img} alt={img} className="img-fluid"/>
<span style={{cursor: 'pointer'}}>
<i class="far fa-trash-alt" onClick={e => deleteImage(img.name, e)}></i>
</span>
</div>
Upvotes: 0