I am using react final form for validation purpose for login page which has forgot password and register link as well, now when I am clicking forgot password or register link ,it should not trigger any validation even though I am not filling my user name and password .I have tried t keep forgot password and register link away from tag but it is still triggering the validation on click of forgot password and register link .It should only trigger the validation when I m hitting submit button.
It should not ask to validate the form when I am clicking on any hyper link on the page as hyperlinks does not have any validations.
Here is the code sample
loginPage = () => {
const {t: translate} = this.props;
const {
match: {
params: {
authUrlKey = ''
} = {},
} = {},
} = this.props;
return (
<Form
onSubmit={ (values)=> this.validateUserCredentials(values)}
render={({ handleSubmit}) => (
<form onSubmit={handleSubmit}>
<button className="hidden" type="submit"/>
<h1 className="hw-block--pb">{translate('login.heading')}</h1>
<p className="hw-text-lead hw-block--pb-small">{translate('login.text')}</p>
{ this.state.description !=='' && <p className="hw-text-lead hw-block--pb-small">{this.state.description}</p> }
<div className="hw-grid">
<div className="hw-grid__item hw-one-whole hw-medium--one-fifth hw-large--one-sixth">
<label className="hw-label">{translate('login.landcode')}
<Field name="landcode" component={Dropdown} options={getCountryList()} onOptionSelect={this.onCountrySelect}/>
</label>
</div>
<div className="hw-grid__item hw-one-whole hw-medium--four-fifths hw-large--five-sixths">
<label className="hw-label">{translate('login.mobileNumber')}
<Field type="text" component={InputType}
validate={composeValidators(mobileNumberRequired, validMobileNumberWithISDCode)}
placeholder={translate('login.mobileNumberPlaceHolder')} name="phoneNumber"/>
</label>
</div>
</div>
<label className="hw-label">{translate('login.password')}
<Field type="password" component={InputType} validate={passwordRequired} placeholder={translate('login.passwordPlaceHolder')} name="password"/>
</label>
<Link className="hw-link" to={{ pathname: '/password/reset', state: {authUrlKey} }}>{translate('login.forgotPassword')}</Link>
<ErrorInfo error={this.state.error} errorMessage={this.state.errorMessage} translate={translate}/>
<div className="hw-block hw-block--mt-small">
<div className="hw-grid">
<div className="hw-grid__item hw-small--one-whole hw-medium--one-quarter hw-block--mb-smaller">
<button className="hw-button hw-button--primary hw-button--full" type="submit">{translate('login.loginButton')}</button>
</div>
<div className="hw-grid__item hw-one-whole hw-medium--three-quarters hw-block--mt-smaller">
<Link className="hw-link"
to={{ pathname: '/register', state: {authUrlKey} }}>{translate('login.registerButton')}</Link>
</div>
</div>
</div>
</form>)}
/>
)}
validations function used in code
export const validMobileNumberWithISDCode = (fieldValue='') => {
const value = trimValue(fieldValue);
const regex1 = /^\+?((45)|(46)|(47))?( )?\d{8,10}$/
return (regex1.test(value))? undefined : message[root.lang].validMobileNumber;
}
export const validMobileNumber = (fieldValue='') => {
const value = trimValue(fieldValue);
const regex1 = /^\d{8,10}$/;
return (regex1.test(value))? undefined : message[root.lang].validMobileNumber;
}
export const mobileNumberRequired = (fieldValue='') => {
const value = trimValue(fieldValue);
return value ? undefined : message[root.lang].mobileNumberRequired;
}
export const passwordRequired = (fieldValue='') => {
const value = trimValue(fieldValue);
return value ? undefined: message[root.lang].passwordRequired;
}
export const required =(fieldValue)=> {
const value = trimValue(fieldValue);
return value ? undefined : message[root.lang].required;
}```
validateUserCredentials -> This function does not contains any validation.It is used to retrieve form values and send it to server
React Final Form calls your validation function on every value change in the form, to ensure that the form validity is always up to date. Since you did not include the code for your validation function, I cannot ascertain what you are attempting to do. Your validation function should be very cheap to run (e.g. required fields, value length, etc.). The actual authentication should happen on submit.
Related
I am trying to display an error message when nothing is typed inside the message input form, but when I load the page I get this error 'TypeError: Cannot read property 'message' of undefined'. I am using react-hook-forms. This is my code down below.
import { Button } from "#material-ui/core";
import { Close } from "#material-ui/icons";
import React from "react";
import { useForm } from "react-hook-form";
import "./SendMail.css";
const SendMail = () => {
const { register, handleSubmit, watch, errors } = useForm();
const onSubmit = (formData) =>{
console.log(formData)
}
return (
<div className="sendMail">
<div className="sendMail__header">
<h3>New Message</h3>
<Close className="sendMail__close" />
</div>
<form onSubmit={handleSubmit(onSubmit)}>
<input name='to' placeholder="To" type="text" {...register('to',{required:true})}/>
<input name="subject" placeholder="Subject" type="text" {...register('subject',{required:true})} />
<input
name="message"
placeholder="Message..."
type="text"
className="sendMail__message"
{...register('message',{required:true})}
/>
{errors.message && <p>To is required!!</p>}
<div className="sendMail__send">
<Button
className="sendMail__send"
variant="contained"
color="primary"
type="submit"
>
Send
</Button>
</div>
</form>
</div>
);
};
export default SendMail;
Since v7 the errors object moved to the formState property, so you need to adjust your destructering:
const { register, handleSubmit, watch, formState: { errors } } = useForm();
I'm building a simple html form using "react-hook-form" library: https://react-hook-form.com/
I've incorporated "react-bootstrap-typeahead" into the html form but haven't been able to register this component with 'useForm' hook. Hence, "react-bootstrap-typeahead" input data is ignored during onSubmit.
"react-bootstrap-typeahead" doesn't provide a "name" prop which makes it difficult to register the component.
I've read the 'useForm' documentation on the different options for registering this type of components but still don't understand how to achieve this: https://react-hook-form.com/get-started#Registerfields
Does anybody have faced such challenge before?
It would be great to see a working example to get a better idea on how to implement "react-bootstrap-typeahead" + "react-hook-form" in my application. Thanks!
Here's my sample code:
import useForm from 'react-hook-form';
import { Typeahead } from 'react-bootstrap-typeahead';
import 'react-bootstrap-typeahead/css/Typeahead.css';
const myForm = (props) => {
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => {
// api post request with form data
})
};
const mydata = [ "one", "two", "three" ];
return (
<>
<form onSubmit={handleSubmit(onSubmit)} >
<div className="form-group">
{/* Here I'm registering text input using ref: */}
<input type="text" className="form-control" name="name" ref={register({ required: true })} />
</div>
<div className="form-group mb-0">
{/* How can I register the below component with useForm? */}
<Typeahead
id="multiple-typeahead"
clearButton
multiple
options={mydata}
/>
</div>
<button type="submit">Save</button>
</form>
</>
);
}
This is how i was able to register the component:
import useForm from 'react-hook-form';
import { useForm, Controller } from "react-hook-form";
import 'react-bootstrap-typeahead/css/Typeahead.css';
const myForm = (props) => {
const { register, handleSubmit, errors, control } = useForm();
const onSubmit = data => {
// api post request with form data
})
};
const mydata = [ "one", "two", "three" ];
return (
<>
<form onSubmit={handleSubmit(onSubmit)} >
<div className="form-group">
<input type="text" className="form-control" name="name" ref={register({ required: true })} />
</div>
<div className="form-group mb-0">
<Controller
as={Typeahead}
control={control}
name="typeahead_component"
rules={{ required: true }}
id="multiple-typeahead"
clearButton
multiple
options={mydata}
defaultValue=""
/>
</div>
<button type="submit">Save</button>
</form>
</>
);
}
Because we cannot assume our components are singletons: I am trying to automatically handle giving htmlFor to a label and field. We see below I use useMemo and lodash uniqueId to memoize a unique id for the form on initial render. I had to give useMemo and empty array as second argument so it never re-calculates the id. Is there some automated way to handle this in final-form?
import React, { useMemo } from 'react';
import { Form, Field } from 'react-final-form';
import { uniqueId } from 'lodash';
function TaskForm() {
const id = useMemo(() => uniqueId('_form'), []);
const getFor = name => name + id;
return (
<>
<h3>Create a task</h3>
<Form onSubmit={onSubmit}>
{({ handleSubmit, pristine, invalid, ...rest }) => {(
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor={getFor('firstName')}>First Name</label>
<Field name="firstName" id={getFor('firstName')} component="input" placeholder="First Name" />
</div>
<button type="submit" disabled={pristine || invalid}>Submit</button>
</form>
)}}
</Form>
</>
);
}
I am trying to create a Wizard form using react-final-form by referring to this code https://codesandbox.io/s/km2n35kq3v. For my use case I need some mutator functions to be used inside my form fields. This example illustrates how to do that - https://codesandbox.io/s/kx8qv67nk5?from-embed.
I am not sure how to access mutator functions in my form steps when I am using a wizard form instead of a single page form.
I tried to combine both the examples by modifying the <Form> component rendered by Wizard.js to pass in the mutators. However I cannot access these mutators in the Wizard form pages.
In Wizard.js
return (
<Form
mutators={{
// potentially other mutators could be merged here
...arrayMutators,
}}
render={({
handleSubmit,
submitting,
values,
pristine,
invalid,
form: {
mutators: {push, pop, remove},
},
}) => {
return (
<form onSubmit={handleSubmit}>
Another file index.js
<Wizard
initialValues={{ employed: true, stooge: "larry" }}
onSubmit={onSubmit}
>
<Wizard.Page>
<FieldArray name="customers">
{({ fields }) =>
fields.map((name, index) => (
<div key={name}>
<label>Cust. #{index + 1}</label>
<Field
name={`${name}.firstName`}
component="input"
placeholder="First Name"
/>
<span
onClick={() => fields.remove(index)}
style={{ cursor: "pointer" }}
>
❌
</span>
</div>
))
}
</FieldArray>
</Wizard.Page>
</Wizard>
It errors out - remove is undefined in index.js
Look at this working example: https://codesandbox.io/s/znzlqvzvnx
changes I have made:
Wizard.js
static Page = ({ children, mutators }) => {
if(typeof children === 'function'){
return children(mutators);
}
return children;
};
...
<form onSubmit={handleSubmit}>
{
// activePage
<activePage.type {...activePage.props} mutators={mutators} />
}
...
index.js (only first <Wizard.page>)
<Wizard.Page>
{
({ upper }) => (
<React.Fragment>
<div>
<label>First Name</label>
<Field
name="firstName"
component="input"
...
</div>
</React.Fragment>
)
}
</Wizard.Page>
I am trying to send a POST request from axios to a Rails API using the following function in the React frontend:
export function registerUser({ name, email, password }) {
var postdata = JSON.stringify({
auth: {
name, email, password
}
});
return function(dispatch) {
axios.post(`${API_URL}/user_token`, postdata )
.then(response => {
cookie.save('token', response.data.token, { path: '/' });
dispatch({ type: AUTH_USER });
window.location.href = CLIENT_ROOT_URL + '/dashboard';
})
.catch((error) => {
errorHandler(dispatch, error.response, AUTH_ERROR)
});
}
}
The Knock gem expects the request in the following format:
{"auth": {"email": "foo#bar.com", "password": "secret"}}
My current function seem to generate the correct format (inspecting the request in the browser devtools), but I'm getting the following error:
Uncaught (in promise) Error: Objects are not valid as a React child
(found: object with keys {data, status, statusText, headers, config,
request}). If you meant to render a collection of children, use an
array instead or wrap the object using createFragment(object) from the
React add-ons. Check the render method of Register.
class Register extends Component {
handleFormSubmit(formProps) {
this.props.registerUser(formProps);
}
renderAlert() {
if(this.props.errorMessage) {
return (
<div>
<span><strong>Error!</strong> {this.props.errorMessage}</span>
</div>
);
}
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
{this.renderAlert()}
<div className="row">
<div className="col-md-6">
<label>Name</label>
<Field name="name" className="form-control" component={renderField} type="text" />
</div>
</div>
<div className="row">
<div className="col-md-12">
<label>Email</label>
<Field name="email" className="form-control" component={renderField} type="text" />
</div>
</div>
<div className="row">
<div className="col-md-12">
<label>Password</label>
<Field name="password" className="form-control" component={renderField} type="password" />
</div>
</div>
<button type="submit" className="btn btn-primary">Register</button>
</form>
);
}
}
The error is caused by the following line in your code
errorHandler(dispatch, error.response, AUTH_ERROR)
The exception raised clearly explains that. Instead of setting error.response, try to use the actual data from error.response. E.g error.response.data. Also, you can try replacing the error.response with a string and see how that behaves, then reference the string you need from error.response.data.