I am working on a login page where I am using redux-form. I want to disable the submit button until email and password are filled. I tried but I am failed, could someone please help me how to achieve my goal. Thanks
Code
<form onSubmit={handleSubmit}>
<div className="sign-up-form">
<div className="space-2">
<Field
name="email"
component={renderField}
type="email"
label="Email"
/>
</div>
<div className="space-2">
<Field
name="password"
component={renderField}
type="password"
label="Password"
/>
</div>
{/* <button className='login-button' type='submit'>Login</button> */}
<div className="">
<button className="login-button" type="submit">
{loading ? (
<Loader
type="ThreeDots"
color="#ffffff"
height="10"
width="100"
/>
) : (
"Login"
)}
</button>
</div>
</div>
</form>
You can check this link handleSubmit and props:
https://redux-form.com/6.0.0-alpha.4/docs/api/props.md/
const {invalid} = this.props
return(
<button type="submit" className="send-btn"
disabled={invalid|| submitting || pristine}>
submit
</button>)
A possible way of doing this is use redux-form selectors to read the input values and return a property indicating if the button should be enabled or not.
To do so, you need to connect your form to redux state and use mapStateToProps to return the desired value.
Idea:
import { connect } from "react-redux";
import { Field, reduxForm, formValueSelector } from "redux-form";
let MyForm = props => {
const { enableSubmit } = props; // new property set from redux state
return (
<form>
... your form
</form>
}
const selector = formValueSelector("myForm"); // <-- same as form name
MyForm = connect(state => {
const hasUsername = selector(state, "email"); // read username value
const hasPassword = selector(state, "password"); // read username value
const enableSubmit = hasUsername && hasPassword; // logic for enabling the submit button
return {
enableSubmit // this will set property `enableSubmit` which you can read in your component
};
})(MyForm);
I prepared a working example here
Related
I am building a login/signup/reset form. I am encountering a problem which is when on the modal of reset password, I would like to click the button to submit email for reset password. After click the button, I want a new success message modal replace the current modal. But the success message always appear below the current reset password modal. How could solve it? Thank you.
Here is the modal component of reset password
import { useState } from "react";
import { updatePasswordFields } from "../constants/formFields";
import FormAction from "./FormAction";
import Input from "./Input";
import MessageContent from "./Message";
const fields = updatePasswordFields;
let fieldsState = {};
fields.forEach((field) => fieldsState[(field.id = "")]);
export default function ForgotPassword() {
const [resetPasswordState, setResetPasswordState] = useState(fieldsState);
const [showMessage, setShowMessage] = useState(false);
const handleChange = (e) =>
setResetPasswordState({
...resetPasswordState,
[e.target.id]: e.target.value,
});
const handleSubmit = (e) => {
e.preventDefault();
setShowMessage(true);
};
return (
<form className="mt-8 space-y-6" onSubmit={handleSubmit}>
<div className="">
{fields.map((field) => (
<>
<label>{field.labelText}</label>
<Input
key={field.id}
handleChange={handleChange}
value={resetPasswordState[field.id]}
labelText={field.labelText}
labelFor={field.labelFor}
id={field.id}
name={field.name}
type={field.type}
isRequired={field.isRequired}
placeholder={field.placeholder}
/>
</>
))}
<FormAction handleSubmit={handleSubmit} text="Update Password" />
{showMessage && <MessageContent />}
</div>
</form>
);
}
Here is the success message modal
import React from "react";
import { MdMarkEmailRead } from "react-icons/md";
export default function MessageContent() {
return (
<div>
<div className="text-sky-600 text-center w-full flex jutify-center">
<MdMarkEmailRead size={44} />
</div>
<div className="text-center text-sm mb-10 max-w-[300px] mx-auto">
We have sent the update password link to your email, please check that!
</div>
</div>
);
}
Here is the result what I got so far screenshot
I'm not sure if I get your means..
If you want to show MessageContent() and hide reset password form in the same modal, there is an easy way to get it.
export default function ForgotPassword() {
// ellipsis...
if (showMessage) {
return <MessageContent />
}
return (
<form ...>...</form>
)
}
Why is my code not working? I'm creating a registration form and I'm wanting to add an error message if the passwords do not match. Why is it not letting me dynamically add para tag to my html? Adding some more text here as I'm getting a post is mostly code error......
import React from 'react'
import Navbar from './components/Navbar'
import { Link } from 'react-router-dom'
import './Register.css'
import { useState, useRef } from 'react'
import { createUserWithEmailAndPassword } from "firebase/auth";
import { auth } from './firebase'
function Register() {
const div = useRef(null);
const handleSubmit = event => {
if (password == confirmPassword) {
createUserWithEmailAndPassword(auth, registerEmail, confirmPassword)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
// ..
});
}
else {
//problem
var passNotMatch = document.createElement('p');
passNotMatch.innerHTML = "Passwords do not match, please try again.";
div.appendChild(passNotMatch);
event.preventDefault();
}
}
return (
<>
<Navbar />
<div className='signup-div'>
<div useRef={div}>
<h2>Register</h2>
<form onSubmit={handleSubmit}>
<input className='input input_email' type="email" placeholder='Email Address' value={registerEmail} onChange={e => setRegisterEmail(e.target.value)} required /> <br />
<input className='input input_password' type="password" placeholder='Set password' value={password} onChange={e => setPassword(e.target.value)} required /> <br />
<input className='input input_password' type="password" placeholder='Confirm password' value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} required /> <br />
<button type='submit' className='register-button'>Register</button>
<Link to='/signin'>Already have an account? Sign In</Link>
</form>
</div>
</div>
</>
)
}
You're using React incorrectly. Directly interacting with the DOM is almost never the right approach in React. Instead, "dynamic" markup is conditionally included in the markup based on state values. For example, consider this markup structure:
return (
<>
<Navbar />
<div className='signup-div'>
<div>
<!-- the rest of your markup, then... -->
{showError ? <p>Passwords do not match, please try again.</p> : null}
</div>
</div>
</>
)
Note the conditional inclusion of the <p> element, based on the boolean value of showError. Which means showError is something you'd track in state:
function Register() {
const [showError, setShowError] = useState(false);
const handleSubmit = event => {
//...
}
//...
}
Its initial value is set to false, so the <p> won't be shown. Then you just update the state to true to show it:
else {
//problem
setShowError(true);
event.preventDefault();
}
You would also set it back to false wherever you want in your code. Perhaps at the beginning of the handleSubmit function for example.
Overall the concept is that you don't directly manipulate the DOM. Instead, you track the current "state" of things in state values. The rendering is based on the current state, and updates to the state trigger a re-render.
I'm new to React and have been trying to make a registration form, but I couldn't find a way to get data from my input when a button is clicked (onClick)
function App() {
const userData = []
function handleClick() {
//get input data here
}
return (
<div className="form-main">
<div className='em'>
<label className='label '> User e-mail </label>
<Input type="email" />
</div>
<div className='pw'>
<label className='label '> Password </label>
<Input type="password" />
</div>
<button type="submit" className="submit-btn" onClick={handleClick}>Signup</button>
</div>
);
}
I've shared my input component below in case that helps (I've shortened the code while posting)
function Input(props) {
return (
<input type={props.type} className="input"></input>
);
}
Your form inputs are uncontrolled - https://reactjs.org/docs/forms.html#controlled-components
Updates to the value of the input aren't being registered by React. A quick stripped down working version to give you an idea of how it works:
const Form = () => {
const [email, setEmail] = useState('');
const handleSubmit = (event) => {
event.preventDefault();
// ... do something with email
}
return (
<form onSubmit={handleSubmit}>
<input type='email' value={email} onChange={(e) => { setEmail(e.target.value) }} />
<button type='submit'>Submit</button>
</form>
);
}
In this way React is 'controlling' the input and you can do whatever you like with the email value in the handleSubmit() function.
You can make use of useRef here . Just call handleSubmit when submit button is clicked as shown below .
const Form = () => {
const emailRef = React.useRef(null);
const handleSubmit = (event) => {
event.preventDefault();
// ... make use of your email data entered inside input
console.log(emailRef.current.value) // consoles the email
}
return (
<form onSubmit={handleSubmit}>
<input type='email' ref={emailRef} />
<button type='submit' onClick={handleSubmit}>Submit</button>
</form>
);
}
You can get more clarity on useRef here official doc
I took the example from the documentation :
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example"));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input defaultValue="test" {...register("example")} />
<input type="submit" />
</form>
);
}
But on every change or on submit, I got undefined for each field
I tried to install the library again but nothing change and I got undefined everywhere...seems to be a problem with the register function. Does anybody got the same issue ?
With v7 the usage of register changed as noted in the comments. If you still need to use v6, you have to write it like this:
function App() {
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example"));
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input defaultValue="test" name="example" ref={register} />
<input type="submit" />
</form>
);
}
Docs v6
In my case it was a typo:
<input defaultValue="test" {...(register('name'), { required: true })} />
// submit => { name: undefined }
Instead of:
<input defaultValue="test" {...(register('name', { required: true }))} />
// submit => { name: "test" }
Hopefully it can help someone else.
In my case, I was using a Controller, so to fix the Undefined value I just had to pass defaultValues to useForm.
See the rules section here: https://react-hook-form.com/api/useform/watch
const { register, handleSubmit, control, setValue} = useForm<MyFormValues>({
defaultValues : {
receiveUpdates: false
}
});
<Controller
control={control}
name="receiveUpdates"
render={({ field }) => (
<FormControlLabel
control={
<Checkbox
ref={field.ref}
checked={field.value}
onChange={field.onChange}
/>
}
label="Receive Email Updates?"
labelPlacement="start"
/>
)}
/>
I had this issue when using the Input component from reactstrap. Using that component made all my values undefined. I switch the Input to a normal input and was able to read in values
Before:
<Input
placeholder="Password"
type="password"
id="password"
defaultValue=""
{...register('password')}
required
/>
Fixed:
<input
placeholder="Password"
type="password"
id="password"
defaultValue=""
{...register('password')}
required
/>
In my case I installed like "npm i react-hook-form" and I don't know why, but it was installed ^6.15.8 version, and I removed it and try again and then it was install correctly. So try to check out your version of react-hook-form
If i have the following dialog/modal:
<Modal
open={this.state.createAccountModalOpen}
trigger={<Link size="m" theme="bare" href="#" className="main-menu-item" onClick={this.handleOpenModalCreateAccount}>Create account</Link>}
closeIcon
onClose={() => { this.setState({
createAccountModalOpen: false,
}); }}
>
<Header icon='add user' content='Create account' />
<Modal.Content>
<Form />
</Modal.Content>
<Modal.Actions>
<Button color='green' onClick={this.handleSubmit}>
<Icon name='add user' /> Create account
</Button>
</Modal.Actions>
</Modal>
Basically this is a React Semantic-ui Modal/Dialog. Now What i want to do is make Form reusable (the Form component contains 4 input fields), so i can use it in other modals or components. What would be the best way so that when I click on Create account, it gathers the data from the form and then submits it?
Do I have to pass functions to the Form to try store the data in the main Modal component? or is there a better way to get the validated data from the form?
I’m on my phone so I’m limited.
You want to define your custom function in the parent component where you call your Modal. Then pass that function to it as a prop modal onComplete={this.submitEmail}
Then in your modal component call this.props.onComplete in your handleSubmit.
Then from here out you can define the custom function you want to use wiTh the model and pass it through with onComplete={whateverFunction}
In order to only show the inputs that you want you could set up a series of render if statements. Then when you call your Modal you can pass through renderIfText={“email”} and in your model if this.props.renderIfText=email render email input.
import React from 'react';
class ReusableModalForm extends React.Component {
constructor(props){
super(props);
this.state ={
};
}
handleChange(e) {
let {name, value} = e.target;
this.setState({
[name]: value,
usernameError: name === 'username' && !value ? 'username must have a value' : null,
emailError: name === 'email' && !value ? 'email must have a value' : null,
passwordError: name === 'password' && !value ? 'password must have a value' : null,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.onComplete(this.state)
}
render() {
return (
<Modal
open={this.state.createAccountModalOpen}
trigger={<Link size="m" theme="bare" href="#" className="main-menu-item" onClick={this.handleSubmit}>{this.props.buttonText}</Link>}
closeIcon
onClose={() => { this.setState({
createAccountModalOpen: false,
}); }}
>
<Header icon='add user' content='Create account' />
<Modal.Content>
<Form />
</Modal.Content>
<Modal.Actions>
<Button color='green' onClick={this.handleSubmit}>
<Icon name='add user' /> {this.props.buttonText}
</Button>
</Modal.Actions>
</Modal>
);
}
}
export default ReusableModalForm;
In order to make your <Form /> reusable you need to determine what are the inputs/outputs to your Form and allow any potential parent component to access/manipulate it via props.
Perhaps something like:
<CreateAccountForm
input1DefaultValue={...}
input2DefaultValue={...}
onSubmit={yourCreateAccountFormHandler}
/>
Do I have to pass functions to the Form to try store the data in the main Modal component? or is there a better way to get the validated data from the form?
It depends on how you implement Form and your input fields.
I would recommend react-form library or, if you want to have your own implementation - using redux state and wire your inputs/form to redux.
If no redux then you will need to store the state of inputs in the modal.
Whenever you compose components, you share data between them using props. I will be passing "name and label" props to stateless functional component named;
input.js
import React from "react";
const Input = ({name,label}) => {
return (
<div className="form-group">
<label htmlFor={name}>{label}</label>
<input
autoFocus
name={name}
id={name}
className="form-control"
aria-describedby="emailHelp"
/>
);
};
export default Input;
form.js
import React, { Component } from "react";
import Input from "./common/input";
class RegisterForm extends Form {
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input name="username" label="username" />
<input name="email" label="email" />
<input name="password" label="password" />
</form>
</div> ); } }