How can I use a label for file upload? - javascript

I am newbie on react. I have asked few days back regarding the upload on image by modifying the button through some div. I have thought to do it by hooks (based on my research)
One of the user has suggested me that use the label and on the use the htmlFor attribute with using the same id used on the input types file.
I have used but the problem is that on my image filed in the state where i am using to store the base64 uploaded string was wiped out through some kind of event bubbling or some other reason. On final submit, I did not get the image on state.
I have found that using Label will make some bubbling and my image in state will be refreshed with default value
This is my implementation:
constructor(props, context) {
super(props, context);
}
postQuery=()=> {
// This function trigger when final submit button is clicked and here i am not getting
the image key with value in state.
console.log('Final State: ', this.state); // Here i need the image in state
// Other task is dependent on this.state.image; // ---> base64 string;
}
uploadImage()=> {
// here I am getting the file which is selected by the user from frontend.
// some function which return the image base64 string
let fileToLoad = e.target.files[0]
// here call the base64 function which is returning the base64 string
this.setState({
image: fileToLoad.base64,
}, ()=> { console.log(this.state.image) }); // here I am getting the image key with base64 string on state.
}
render() {
<div>
<Button onClick={()=>this.postQuery()}>SUBMIT</Button>
</div>
<div>
<FormControl
id="formControlsFile"
type="file"
label="file"
onChange={(e) => this.uploadImage(e)}
style={{display: 'none'}} // if change to display block and click on the input then everything works correct.
/>
<label style={{ display: 'inline-block' }} htmlFor="formControlsFile">
<i
className={cx(
fontStyles.fa,
fontStyles["fa-image"]
)}
/>
<span>UPLOAD IMAGE</span>
</label>
</div>
}
Can anyone guide me where I need to fix/modify. Any suggestion or help is highly appreciated.
Thanks in advance for the interactions.

What worked for me using material-UI was this piece of code
const [mainImage, setMainImage] = useState(null);
const handleCapture = ({ target }) => {
setMainImage(target.files[0]);
uploadImage("main", target.files[0]);
};
<Button
variant="contained"
component="label"
sx={{ width: "100%" }}
>
Upload Image
<input
hidden
id="faceImage"
type="file"
// multiple
accept="image/*"
onChange={handleCapture}
/>
</Button>

Related

ReactJS // SearchBar onClick button

I created this search bar for an API. As you can see, the search bar is working with an onChange event. The user is searching the movie thanks to the title. I would like to search a movie with an onClick event with the button. For example, I'm searching Titanic, only this movie must appear.
<form action='/' methode='get' className='Search-Bar'>
<input
type='text'
id='searchbar'
className='searchbar'
placeholder='Rechercher un titre, un réalisateur...'
onChange={(e) => {
setSearchMovie(e.target.value);
}}
/>
<button className='search-button'>
<AiOutlineSearch /> OK
</button>
</form>
This is my code for the filter :
const allMovies = movies
.filter((value) => {
if (searchMovie === '') {
return value;
} else if (value.title.includes(searchMovie)) {
return value;
}
})
.map((movie, index) => {
return ( .............
It's working but I don't know how to search a movie thanks to the button... do you know how can I do this ??
Thank you !
Assuming your onClick is on the button it would be something like this, where you set the value of the movie as the value of the input field.
With your onChange set a value in the component for searchFieldValue and use it with the onClick. Ps your code is only html and JS as far as i can see, not a react related issue.
<button
className='search-button'
onClick={(e) => {
setSearchMovie(searchFieldValue);
}}
>
<AiOutlineSearch /> OK
</button>

Proper way to change Form.Control text with custom onChange

I noticed today that while using a custom onChange in a Form.Control that the text in the field no longer changes when a file is selected. I have looked through the documentation on the Git HERE but it doesnt say how to change the text with a custom event.
my code:
// handles when a file has been selected.
const handleUploadChange = (event) =>
{
setFileToUpload(event.target.files[0]);
setIsFilePicked(true);
}
// Footer containing buttons and file selection
const CardFooter = () =>{
return(
<Card.Footer>
<div style={{width:"80%", display : "flex", flexDirection: "row", justifyContent: "center"}}>
<div style={{marginRight: "40px"}}>
<Form.Group controlId="formFile" className="mb-3">
<Form.Control type="file" custom onChange={handleUploadChange} label={fileToUpload === null ? "No File Selected" : fileToUpload.name}/>
</Form.Group>
</div>
<div className="btn-red" style={{marginRight: "40px"}}>
<Button disabled={fileToUpload === null} onClick={()=>{setFileToUpload(null); setIsFilePicked(false);}}>Clear</Button>
</div>
<div>
<Button disabled={(fileToUpload === null) || (fileToUpload.size >= maxUploadSizeInBytes)} onClick={()=>handleSubmit(fileToUpload)}>Upload</Button>
</div>
</div>
</Card.Footer>
)
}
As you can see here, once a file is selected, my change event happens, but the selection box still reads "No file chosen". I have attempted label, text, displayName , and placeholder like so: label={fileToUpload === null ? "No File Selected" : fileToUpload.name}
Does anyone know the proper prop to use with a custom onChange ?
You can't control input of type "file" in React. When you choose a file, the text/"label" should automatically be updated. You don't have to manage it. Just set the state on select and read the state on submission. To fix your clear button, you could use useRef:
const fileInputRef = useRef(null);
...
<Form.Control ref={fileInputRef} ...>
...
<Button onClick={() => {
setFileToUpload(null);
fileInputRef.current.value = null;
}}>
Clear
</Button
Also consider following:
You don't need your "isFilePicked" state. It can be derived from "fileToUpload" with Boolean(fileToUpload).
There is no Form.Control custom property.
Nore there is a Form.Control label property. If you need a label, add Form.Label to it. You can hide the file input and style your own input solution if you want to.
Codesandbox:
https://codesandbox.io/s/beautiful-vaughan-zn68t
Read more:
how to hold file input value in react
How to reset ReactJS file input

Please is there any way i can get access to a key 🗝 that matches a value selected on a dropdown in JavaScript?

I am learning Javascript / React and I have been doing this react project to make memes and I have all the data regarding the memes in an array of objects but I am stuck now for days without getting it to do what I want.
Inside each object is a name with a value, an ID with a value, A blank with the image URLs. I want to display the names to the user in a dropdown and I want to get access to the ID and blank value of the selected name from the dropdown so that I can feed the image to the user.
I have tried extracting the names and the IDs into separate strings and check for a matching word but sometimes the string value of the ID is not even included in the string values of the name, so that didn't work at all and now I did it like a kind of a hack with a counter that increases each time the onChange function is called and I used the number to feed the image according to the index matching the number but this gives me the wrong image anytime that a user decides to choose image randomly. This may sound a bit abstract so I have included some screenshots here and my code with a link to a code sandbox where all the program lives and hoping to get the help that I need, please.
Hers is the Code Snippets;
export default function MyComponent() {
const [bulkImageArray, setBulkImageArray] = useState([]);
const [counter, setCounter] = useState(1);
const [imageUrls, setImageUrls] = useState();
const [imagesNames, setImagesNames] = useState();
// This is the function that should get me access to the object id value when any value is selected.
function handleChange(event) {
setCounter(counter + 1);
console.log('You just selected: ' + event.target.value);
// setImagesNames(event.target.value);
setImagesNames(bulkImageArray[counter].name);
setImageUrls(bulkImageArray[counter].blank);
console.log(typeof event.target.value);
}
return (
<div>
<select onChange={handleChange}>
{bulkImageArray.map((item) => (
<option key={item.id}>
{/* {item.id} */}
{item.name}
</option>
))}
</select>
<img src={imageUrls} alt={imagesNames} />
<div>
{bulkImageArray.map((item) => (
<img
style={{
width: '400px',
height: '400px',
cursor: 'pointer',
}}
key={item.id}
alt={item.name}
src={item.blank}
/>
))}
</div>
</div>
);
}
}
screenshots:
Array of Objects Structure:
Single Object Structure:
Function Tigered on select:
The dropdown for users to select the image:
I don't know if all this information is enough but this is the code sandbox to the complete project.
Thanks in advance.
You should add value={item.id} to option, so that select onChange can select the value to id, then use the id to find the selected item.

React component not sending variable value with onChange event

I am trying to display more than one task using the same react component and a map function. The components is supposed to upload a file and display the file that has been upload or is uploading with an onChange event, an onSubmit event will be added later to send the file to the back-end. Since the component is being dynamically rendered with an onChange event I am sending the li key as a parameter then only rendering the filename to the li that matches based on the key. The issue I am currently having is when I send the key in the onChange the value is not getting to the function. I have even tried setting a state for the key and then pulling that into the function but I get back undefined I have tried 100 other things as well and either get back undefined or 0. This is my first post on here and I am also just a junior dev so I may be missing info needed here if so please let me know.
Here is the code
const onChange = (e, index) => {
setFilename(e.target.files[0].name)
setArrFiles([...arrFiles, {key:index, file:e.target.files[0].name} ])
}
const displayTask = (index) => {
let upload = []
arrFiles.forEach(el => {
if(el.key === index) {
upload.push(el.file)
}
})
return upload.map((file) => (
<li key={index}>{file}</li>
))
}
{database.map((task, index) => (
<li key={index}>
<p>{index}</p>
<div className="userPortal__tasksContainer">
<div className='userPortal__tasksHeader'>
<p className='userPortal__tasksHeaderTitle'>{task.taskTitle}</p>
<p className='userPortal__tasksHeaderInfo'>{task.taskMessage}</p>
</div>
<div className='userPortal__tasksBodyButtons'>
<form className='userPortal__fileUpload'>
<input className='userPortal__inputButton' multiple id='file' type="file" onChange={e => onChange(e, index)}/>
<label htmlFor='file'>Choose File</label>
</form>
<button className='userPortal__tasksBodyButton green'>Task Complete</button>
</div>
<p id='userPortalFooterTitle'>Successfully Uploaded</p>
<div className='userPortal__footer'>
<ul>
{displayTask(index)}
</ul>
</div>
</div>
</li>
))}
The issue here was like a dummy I hard coded the input ID so when referencing the input field it would only get the hard coded value instead of the index of the component.
Here is the updated form.
<form className='userPortal__fileUpload'>
<input className='userPortal__inputButton' multiple id={index} type="file" onChange={(() => (e) => onChange(e, index))()}/>
<label htmlFor={index}>Choose File</label>
</form>
No Do It Like This
const onChange = (e, index) => {
setFilename(e.target.files[0].name);
// Okay You Need To Filter The State In Order To Get The Object With THe Current Index
// Set The File Value Of The Object To e.target.files[0].name
setArrFiles((state) => {
const allFiles = state;
const currentFile = allFiles.filter(
(file) => parseInt(file.key) === parseInt(index)
)[0];
// i converted it to an integer just to prevent further bugs
currentFile.file = e.target.files[0].name;
return [allFiles];
});
};

Form input very slow / delayed when typing

I have a form comprised of 2 objects - A and B both objects have around 20 variables in them.
When it type there is a couple of seconds delay before the state is updated with the value.
My state is along the lines of this where the data is passed in from a parent component:
export class Booking extends Component<any, BookingProps & BookingState> {
constructor(bookingProps: BookingProps) {
super(bookingProps);
this.state = {
a: bookingProps.a,
b: bookingProps.b,
errors: {}
... around six other objects for modal, default data etc
};
}
Many of the input form form fields are like this:
<Form.Field>
<label htmlFor="ref">Ref</label>
<input
placeholder="Ref"
value={this.state.a.ref}
id="ref"
onChange={this.handleBookingFieldChange}
style={{ backgroundColor: 'lightgrey' }}
/>
</Form.Field>
In the other form fields part of state.b it is exactly the same except the value is this.state.b.ref and the onChange is onChange={this.handleBookingExtrasChange}.
So essentially i have separate onChange handlers for state a and b:
private handleBookingFieldChange = (e: any) => {
const key = e.target.id;
const value = e.target.value;
this.setState({
booking: { ...this.state.a, [key]: value }
});
};
So when i type it takes around 3 seconds for the letters to appear in the text field. I'm new to React (from Angular) and can't think why this would take so long to display what i typed.
I would guess that the state is updating every field but i'm not sure. What can i do to speed it up?
I found that by switching the input a little will work as you type - essentially setting defaultValue instead ofvalue and using onBlur instead of onChange. Now the form fields update when typing:
<Form.Field>
<label htmlFor="ref">Ref</label>
<input
placeholder="Ref"
defaultValue={this.state.a.ref}
id="ref"
onBlur={this.handleBookingFieldChange}
type={'number'}
/>
</Form.Field>

Categories

Resources