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
Related
i am trying to make my button disappear if my textarea is empty
until now i have made some code for it but i still cant do it
in the code i am trying to make the css dynamic by having it change accoring to some ternery condition id the condition is met the css will allow the button to work and if not the other css class will turn the button off
my problem is that i want the on/off condition to work only when the textfield has more than one letter ( is not empty ) this will help me in my posting application as it will not post any empty posts instead only posts with letters and words ( non empty textarea) will post
here is the code:
function PostingNow() {
const [post, setPost] = useContext(Mycontext);
const tw = useRef('')
const[count,setCount] = useState(false)
return (
<div >
<textarea placeholder='whats up?' className="box" ref={tw}></textarea>
<button className={count?'tweetbutton':'unclickable'} >
Tweet
</button>
</div>
{post.map((post, i) => (
<Postingcomponent name ='user name'image={Photo} key={i} postContent={post}/>
))}
</div>
);
}
export default PostingNow
You can conditionally render your button in the jsx.
First make your textarea a controlled component so you have access to its state.
Then write
{textAreaText && <button ... />}
Make the textarea to be a controlled input
const [textarea, setTextarea] = useState("")
...
<textarea onChange={e => setTextarea(e.target.value)}>{textarea}</textarea>
Then for the button:
{textarea && <button ... />}
For better UX, it's recommended to disable the button instead of removing it from DOM.
<button disabled={!textarea} ... />
If you make the TEXTAREA tag something like:
<textarea placeholder='whats up?' className="box" ref={tw} class='unclickable'
onkeyup="fixPostButton(this, 'postButton', 'unclickable', 'tweetbutton');">
And make the BUTTON:
<button id="postButton" class="unclickable">Tweet</button>
Then this javascript will change the class after each keystroke:
<script>
function fixPostButton(txta, butn, isempty, notempty) {
var classX = (txta.value == '') ? isempty : notempty ;
document.getElementById(butn).className = classX; }
</script>
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>
I created one form control using the React Multiselect component. In this control, I want the 'required' to be removed when at least two of the Multiselect fields are selected.Required does not appear when user selects even one. Required appears only when nothing is selected. How can I do that?
React JS
const changeSelected = (selectedList, selectedItem) => {
const values = selectedList.toString();
setInput({...input, value: values})
dispatch(saveAnswer('f3', formKey, values))
}
return (
<>
<p>{comboboxName}</p>
<Multiselect className='btn-group'
style={{background: "red"}}
isObject={false}
closeIcon="close"
options={options} // Options to display in the dropdown
selectedValues={input.value ? input.value.split(',') : []} // Preselected value to persist in dropdown
onSelect={changeSelected} // Function will trigger on select event
onRemove={changeSelected} // Function will trigger on remove event
placeholder=''
/>
<p></p>
<Form.Check>
<Form.Check.Input required
checked={input.value != null && input.value.length > 1}
style={{display:'none' }}
/>
<Form.Control.Feedback type="invalid" >Required</Form.Control.Feedback>
</Form.Check>
</>
)
I guess this would solve your problem:
<Form.Check.Input
required = {input.value.length < 2 ? true : false}
checked={input.value != null && input.value.length > 1}
style={{display:'none' }}
/>
I am trying to implement restriction or validation in a react-datepicker component. I am using redux-form for validation and normalization(to implement restriction)
https://redux-form.com/6.0.0-rc.1/examples/normalizing/
Question : I have observed that neither normalizing function nor validation functions of redux-form is called when we try to enter something in the field
although this value is not submitted when we submit the form but i need to show some validation error or restrict user from typing invalid characters.
I made a wrapper for the date picker component and used it in my form through redux field
my date picker component :-
return (
<div className={"render-date-picker "}>
<div className="input-error-wrapper">
{(input.value) ? <label> {placeholder} </label> : ''}
<DatePicker className="input form-flow" {...input}
placeholderText={placeholder}
selected={input.value ? moment(input.value) : null}
maxDate={maxDate || null}
minDate={minDate || null}
dateFormat={isTimePicker ? "LLL" : "DD/MM/YYYY"}
showYearDropdown
showMonthDropdown
disabledKeyboardNavigation
/>
{touched && error && <span className="error-msg">{t(error)}</span>}
<span className="bar" style={{ 'display': this.state.is_focus ? 'block' : 'none' }} ></span>
</div>
</div>
);
redux form field :-
<Field
name="date_of_birth"
type="text"
className="input form-flow extra-padding-datepicker"
component={RenderDatePicker}
maxDate={moment().subtract(18, "years")}
validate={[required, dateOfBirth]}
normalize={isValidDateFormat}
placeholder={t("DOB (DD/MM/YYYY)")}
/>
my normalizing function:-
export const isValidDateFormat = (value, previousValue) => {
if (value == null || !value.isValid()) {
return previousValue;
}
return value;
}
react-datepicker provides onChangeRaw property to get raw (typed) value inside the datePicker. In order to restrict or validate the datepicker input field we need the raw value which is not available on onChange event of the datepicker component.
for instance if we observe the onChange event :-
It returns a moment object.
In order to get raw value we use onChangeRaw
The raw value is obtained simply from e.target.value.
In my case I simply restrict the user from typing anything in the datepicker input field by a simple function:-
handleChangeRaw = (date) => {
let s=document.getElementById(date_picker_id)
s.value =moment(this.props.input.value).format("DD/MM/YYYY");
}
My datepicker component :-
<DatePicker
.....
disabledKeyboardNavigation
onChangeRaw={(e)=>this.handleChangeRaw(e)}
id={date_picker_id}
.....
/>
This solved my problem. Hope it is useful :)
I have a form where menu has to be uploaded with menu title and type. The type can be food-menu and beverage-menu. Each type will have only 3 images. I have done that part
but when selecting the radio button for menu type, if i select second or other than first radio button, the first radio button gets selected. How do I solve this issue?
The code can be large so here is the demo
https://codesandbox.io/s/zxxrnw2qx4
here is the code in brief
const Preview = props => {
return (
<div>
{props.files.map((file, index) => {
if (['image/png', 'image/jpg', 'image/jpeg'].includes(file.type)) {
return (
<ClientUploadedImage
key={index}
file={file}
id={index}
menu_title={props.menu_title}
type={props.type}
foodmenuError={props.foodmenuError}
handleChange={props.handleChange}
handleTypeChange={props.handleTypeChange}
/>
);
}
return <div>No File to Show Preview</div>;
})}
</div>
);
};
const ClientUploadedImage = props => {
return (
<section id="menus-photo">
<img src={props.file.preview} width={'400px'} height={'auto'} />
<div className="content">
<form className="form">
<Radio
value="food-menu"
label={`Food Menu${props.id}`}
name={props.id}
handleChangeEvent={props.handleTypeChange}
isChecked={props.type[props.id] === 'food-menu'}
/>
<Radio
value="beverages-menu"
label={'Beverages Menu'}
name={props.id}
handleChangeEvent={props.handleTypeChange}
isChecked={props.type[props.id] === 'beverages-menu'}
/>
<InputField
name={props.id}
type="text"
label="Menu Title"
onChange={props.handleChange}
value={props.menu_title[props.id]}
/>
</form>
</div>
</section>
);
};
Your type array is empty in initial state. If you directly select radio button from second image, handleTypeChange is being called with index 1. In the function, ...types.slice(0, index) becomes types.slice(0,1) which eventually performs spread operation on a blank array and your newValue is appended at 0th position which leads to selection of first image radio button. Here you need to handle the blank array condition for first selection inside the function and you will be good to go.