I'm trying reproduce Youtuber Traversy Media's React JS crash course 2021 Task Tracker project with Reactstrap, and using the same method (a component level hook) to create a form with a checkbox in it, and I set up a method, make sure after the form submitted, the text area will be set to empty and the checkbox set to false, and therefore unchecked. When I hit submit, the checkbox had set to false, but remain checked.
From the React dev tool, the value is reset to false and the checkbox should be unchecked, I don't know what went wrong, I did the exact same thing as the video did. I have problem pasting code here, so left out non-related part, like the input text code. Thanks in advance!
const [reminder, setReminder] = useState(false);
const onSubmit = (e) => {
e.preventDefault()
if (!text) {
alert('Please add a task')
return
}
onAdd({ text, day, reminder })
setText('')
setDay('')
setReminder(false)}
{/* checkbox here */}
<div className="mb-3 form-check">
<input
type="checkbox"
id="checkbox1"
className="form-check-input"
value={reminder}
onChange={(e) => setReminder(e.currentTarget.checked)}
/>
<label className="form-check-label" htmlFor="checkbox1">
Set reminder
</label>
</div>
{/* submit button */}
<div className="d-grid">
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
Doing as below would work. Notice I'm using checked and not value as you did, the reason why it's not working for you.
const [reminder, setReminder] = useState(false);
<input
type="checkbox"
id="checkbox1"
className="form-check-input"
checked={reminder}
onChange={(e) => setReminder(e.currentTarget.checked)}
/>
To know more about the difference between value and checked, you can visite this link from MDN.
Related
I have react app with with complex component layout with multiple forms.
I know that placing one form inside another is not allowed. But I have a component which renders a form and must be placed inside my form. To prevent forms be rendered one inside another I use react portal.
But when I try to submit form rendered with portal, first form is also submitted that is unexpected. Looks like I miss something important.
How to prevent first form submit when submitting the second?
Thank you
Simplified example is here
import { createPortal } from "react-dom";
const Portal = ({ children, elm }) => createPortal(children, elm);
export default function App() {
return (
<div className="App">
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 1");
}}
>
First form <input type="text" value="1" />
<Portal elm={document.querySelector("body")}>
Second form{" "}
<form
onSubmit={(e) => {
e.preventDefault();
alert("submit 2");
}}
>
<input type="text" value="2" />
<input type="submit" value="submit 2" />
</form>
</Portal>
</form>
</div>
);
}
I had the same problem, as #EisaRezaei said in the first comment, using e.stopPropagation() in the form inside the portal, and submit type buttons, everything worked fine
please , how can i get over this error of component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
this prevent the input field from showing what i am typing.
const [sellerName, setSellerName] = useState();
const [storeName, setStoreName] = useState("");
...
<form className="registerInputContainer customerEditInput">
<div className="regInput passForm ">
<span className="userEmail">Owner's Full name (Required)</span>
<div className="passwordContainer editCusInputField">
<input
placeholder="your name"
value={sellerName }
onChange={(e) => setSellerName(e.target.value)}
className="passwordInput regInputField"
/>
</div>
</div>
<div className="regInput passForm ">
<span className="userEmail">Store Name (required)</span>
<div className="passwordContainer editCusInputField">
<input
placeholder=""
required
value={storeName || ""}
onChange={(e) => setStoreName(e.target.value)}
className="passwordInput regInputField"
/>
</div>
</div>
...
</form>
i have tried some of the solution i saw on stackoverflow but they are not working . thanks you all
I have some tags that display text they conditionally render <input /> tags by checking whether the edit state is true or false. When true, instead of showing text, I render an <input /> tag to make inline edit.
Everything works well. The only problem is, when one <button> tag changes the edit state to true, then, instead of showing input field for editing where Edit was clicked, every tag renders their input field.
How do I limit this rendering of input field for only those tags from where the edit state was changed by the Edit button click?
My code:
const [ edit, setEdit ] = useState(false);
const isEdit = edit;
<div>
<p>{ !isEdit ? (<span>Email: {userProfile.email} <button onClick={e=>setEdit(!edit)}>Edit</button></span>) : (<span>Email:
<input type="text" placeholder="email"
name="email" onChange={e=>setEmail(e.target.value)}/>
<button type="submit" onClick={addUserEmail}>Save</button></span>
)}
</p>
<p>About: { !isEdit ? (<span> {userProfile.about} <button onClick={e=>setEdit(!edit)}>Edit</button>
</span>) :
(<span>
<input type="text" placeholder="about"
name="about" onChange={e=>setAbout(e.target.value)}
/>
<button type="submit" onClick={addUserAbout}>Save</button>
</span>)
)}
</p>
</div>
There are a couple of solutions, but the cleanest way would probably be to separate those editable fields into their own component since each of them has its own state.
For example, you can create a generic EditableField component similar to this one:
function EditableComponent({defaultIsEditing = false, renderText, renderInput}) {
const [ isEditing, setIsEditing ] = useState(defaultIsEditing);
if(!isEditing){
//Non-edit mode
return (<span> {renderText()} <button onClick={e=>setEdit(!edit)}>Edit</button></span>);
}
//Edit mode
return renderInput();
}
Then use it as this:
<div>
<EditableComponent
renderText={() => <>Email: {userProfile.email}</>}
renderInput={() => (<span>Email:
<input type="text" placeholder="email" name="email" onChange={e=>setEmail(e.target.value)}/>
<button type="submit" onClick={addUserEmail}>Save</button>
</span>)}
/>
{/* ...repeat for all fields */}
</div>
This solution ensures that you don't repeat the same logic over and over. With two fields you might be okay just making two state variables (e.g. isEdit1, isEdit2), but the more you add the more cumbersome it will become.
Another alternative would be to store the name of the input you're editing as state, this will ensure that only one field is edited at a time, but you need to take care of saving old fields when starting to edit new ones
I am trying to use a custom validation function to generate an error when at least one checkbox is not checked. I run a black box test by not checking any of the check boxes, and then submitting the form. The error message appears as intended. However, when I go into select a checkbox and re-submit, the error message still appears. How can I clear the error message once the correct option has been performed? I am using ReactJS. Here is my JavaScript code:
Custom validation function:
function validateForm() {
{/* Custom validation for medium checkbox group. */}
var mediumCheckboxes = document.getElementsByName("medium");
var validMedium = false;
for (var i = 0, len = mediumCheckboxes.length; i < len; i++) {
if (mediumCheckboxes[i].checked) {
validMedium = true;
break;
}
}
if (!validMedium) {
document.getElementById('error-message-checkbox').innerHTML = "Please check at least one medium.";
}
}
HTML in render function:
{/* Checkbox group. User must select at least one medium. */}
<label className="text main"><b>Medium (check all that apply): *</b></label><span id="error-message-checkbox" className="error"></span>
<div>
<label>
<input className="checkbox" type="checkbox" name="medium" ref={register({validate: validateForm})}/><span>Design & Illustration</span>
</label>
</div>
<div>
<label>
<input className="checkbox" type="checkbox" name="medium" ref={register({validate: validateForm})}/><span>Digital Art</span>
</label>
</div>
<div>
<label>
<input className="checkbox" type="checkbox" name="medium" ref={register({validate: validateForm})}/><span>Drawing</span>
</label>
</div>
Is there a way to reset the error messages every time I submit the form?
I'm using the Field-component and setting type=radio and in the component rendering the input I have set checked={props.input.value}. The group currently contains 2 radio buttons, but 1 more will soon be added. I have added initialValues: { method (name of radio button): '201' (value of the one I want checked initially) } to the reduxForm wrapper.
My problem is that when I use the settings mentioned above, the last radio button in the group gets checked initially, but I want to be able to control which radio button that will initially be checked.
Code that renders the input:
export const RadioButton = props => {
return (
<div className="booking-radio-container">
{props.meta.touched &&
((props.meta.error && <label className="errorCheck">
{props.meta.error}</label>) ||
(props.meta.warning && <label>{props.meta.warning}
</label>))}
<label className="container" onClick={() =>
props.changeFunc(props.input.value)}>
{props.label}
<input {...props.input} type={props.type} checked=
{props.input.value} />
<span className="checkmark" />
</label>
</div>
);
}
The Field:
<FormSection name="paymentMethod">
<Field
name="method"
label="Creditcard"
component={RenderRadio}
type="radio"
changeFunc={this.props.selectPaymentMethod}
icon={CreditIcon}
value="201"
/>
<Field
name="method"
label="Invoice"
component={RenderRadio}
type="radio"
changeFunc={this.props.selectPaymentMethod}
icon={InvoiceIcon}
value="101"
/>
</FormSection>
The redux-form wrapper:
reduxForm({
form: 'bookingForm1',
enableReinitialize: true,
validate: ValidateContact,
asyncValidate: AsyncValidate,
asyncBlurFields: ['ContactForm.email'],
initialValues: {
method: '201'
}
})
So, what I want is for the credit card option to be checked initially, regardless of where it is in the list of fields, but if the user clicks on another option it should be set as checked.
I have tried using defaultChecked, but if i clicked the other option it would revert to credit card.
Right now with the setup described above, I can't check the other option, but if i click the checked option it swithces to the unchecked one and the back again.