How to get formvalues in handlechange? - reactjs

In my form I have an onChange event on one of the formfields:
<div>
<label>Last Name</label>
<div>
<Field
name="lastName"
component="input"
type="text"
placeholder="Last Name"
onChange={() => this.handleChange()}
/>
</div>
</div>
When handleChange gets fired I want to get the formvalues :
handleChange(){
//do calculation
console.log('handlechange',this.props.values)
}
At the moment I am getting this.props.values = undefined? How can I get the formvalues?

You'll need to create a custom input.
You'll need to intercept and update redux's input.onChange function.
Optional -- If you want other form values to influence this value, then utilize reduxForm's formSelector with react-redux's connect's mapStateToProps to access formProps within the component in this.props (the working example below already includes this functionality)
components/CustomInput.js
import React from "react";
const CustomInput = ({
// we'll intercept redux's "onChange" func, while leaving the other
// input props as is in "inputProps"
input: { onChange, ...inputProps },
// the "handleChange" func below is the parent func that will handle input changes
handleChange,
// "rest" contains any additional properties (className, placeholder, type ...etc)
...rest
}) => (
// we spread out the "inputProps" and the "rest" of the props, then we add
// an "onChange" event handler that returns the "event" and the
// input's "onChange" func to our "handleChange" parent func
<input {...inputProps} {...rest} onChange={e => handleChange(e, onChange)} />
);
export default CustomInput;
containers/Form.js
class ControlledFormValue extends PureComponent {
// this parent func will handle updates through the "event.target.value";
// the value can be changed/altered and then passed to the input's
// "onChange" func to update the field
handleChange = ({ target: { value } }, onChange) => {
// this will alter the value by adding a "-" after each input update
onChange(`${value}-`);
setTimeout(() => console.log(this.props.values), 500);
};
render() {
return (
<form onSubmit={this.props.handleSubmit}>
<div>
<label>First Name</label>
<div>
<Field
className="uk-input"
name="firstName"
component={CustomInput}
type="text"
placeholder="First Name"
handleChange={this.handleChange}
/>
</div>
</div>
...etc
</form>
);
}
}
Working example: https://codesandbox.io/s/lx1r4yjwy7

Related

The react-hook-form library and React Ref

Having such a simple react-hook-form example form:
import React from 'react';
import { useForm } from 'react-hook-form';
export default function ReactForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const onSubmit = (data) => console.log(data);
let textInput = null;
function handleClick() {
textInput.focus();
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="firstName">First Name:</label>
<input
id="firstName"
ref={(input) => {
console.log("firstName ref...")
textInput = input
}
}
{...register('firstName')} />
<br/>
<label htmlFor="lastName">Last Name:</label>
<input id="lastName" { ...register('lastName', { required: true })} /><br/>
<label htmlFor="age">Age:</label>
<input id="age" {...register('age', { pattern: /\d+/ })} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/><br/>
<input type="submit" />
{errors.firstName && <p>First name is required!</p>}
{errors.lastName && <p>Last name is required!</p>}
{errors.age && <p>Please enter number for age!</p>}
</form>
);
}
I'm getting :
Cannot read properties of null (reading 'focus')
error. The reason for this is that the ref seems not to be called at all (NOT giving the the firstName ref... in the console). Why doesn't the ref NOT being called & working!?
P.S.
I'he rewritten the above WITHOUT using the react-hook-form and the ref do work as expected so the problem lies somewhere in the react-hook-form library!
Your ref prop is being overridden by react-hook-form's register. The result of register includes it's own ref property that you're spreading onto the input. The docs indicate this is used for focusing the field on validation errors.
Your exception occurs in your click handler because your ref callback was never executed (and textInput is still null).
Try swapping the order so you override the ref provided by register('firstName') like so:
<input
id="firstName"
{...register('firstName')} // spread result of register including ref prop
ref={(input) => { // override ref prop
console.log("firstName ref...")
textInput = input
}}
/>

React-Hook-Form Input Element is Empty in Inspect Element but Not in Browser

I am using react-form-hook in a project. I have css styles based on input field value attributes. react-form-hook is setting the values of all the inputs but doesn't show in inspect element niegther my css styles work. I just want to know how react-form-hook set the values on input elements when there is no actual value. Here is the code
import React, { useState } from 'react';
const CustomInput = (props: any) => {
const { label, name, className, type, onChange, register, setValue, value, disabled } = props;
return (
<div className="custom--input--container">
<input
type={type}
name={name}
ref={register}
className={`custom--input ${className}`}
onChange={e => {
onChange();
setValue(name, e.target.value, { shouldValidate: true });
}}
/>
<span className="custom--input--label">{label}</span>
</div>
);
};
export default CustomInput;
Component used here
<CustomInput
label="First Name*"
type="text"
name={SettingsFormFields.FIRST_NAME}
className={classNames({
error: errors[SettingsFormFields.FIRST_NAME],
})}
setValue={setValue}
register={register}
onChange={enableButton}
/>
value is being displaed
No value in inspect element

Automatically Passing Props on Component

I have created an Input component that I have styled with Styled Components. I am now using that Input component with Formik. I would like to be able to automatically set the onChange, onBlur and value props rather than have to set them each and every time (like what happens if I would use the Formik Field component).
That is, right now this is how my component looks when used:
<Input
name="firstName"
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
/>
What I would like the component to look like when being used is this:
<Input name="firstName" />
Then, behind the scenes, onBlur would be set to handleBlur, onChange would be set to handleChange and value would be set to values.[name]. That is, to the value of the name prop. So, in this example, it would be set to values.firstName. If the name prop was set to lastName, then the value prop would automatically be set to values.lastName.
Any idea how I can do this?
NOTE: I know that the Field prop from Formik does this, but I want to use my custom Input component instead.
UPDATE
Here is some other code that may be relevant to answering this question.
Input Component
export const Input = props => {
const {
forId,
name,
placeholder,
} = props
const titleCase = startCase(name)
return (
<InputBase {...props}>
<InputSection>
<InputContent
id={forId ? forId : name}
placeholder={placeholder ? placeholder : titleCase}
type="text"
{...props}
/>
</InputSection>
</InputBase>
)
}
InputContent Component
export const InputContent = styled.input`
// STYLES
`
Formik with Form
<Formik
render={props => {
const {
handleBlur,
handleChange,
values,
} = props
return (
<Form>
<Input
name="firstName"
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
/>
<Button type="submit">Submit</Button>
</Form>
)
}}
initialValues={{firstName: ''}
validationSchema={validationSchema}
/>
I don't think this is good idea. But what you can do is create HOC and wrap it
// lasyWrapper.js
export function lazyWrapper(Input) {
return LazyWrapper extends React.Component {
render() {
return (
<Input
{...this.props}
name={this.props.name}
onBlur={this.props.handleBlur}
onChange={this.props.handleChange}
value={this.props.values[this.props.name]}
/>
)
}
}
}
// Input.js
export default lazyWrapper(Input)
// use somewhere
<Input
name="firstName"
{...this}
/>
But this is really BAD idea.

Setting the default value of an input field after data is retrieved causes the content to overlap and the "onChange" event not to be triggered

I have an "edit category" component in my React application.
The ID is passed through the URL.
When the component is mounted, the action "fetchCategory" is called, which updates the props on the component with the current category.
I have a form which I want to be pre-populated, which I'm currently doing using the defaultValue on the input.
However, this isn't reflected on the state and the label for the text field overlaps the input field.
Any help would be greatly appreciated. I'll leave snippets of my code below which could help with understanding what I'm trying to do.
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchCategory } from "../../store/actions/categoryActions";
class AddOrEditCategory extends Component {
componentDidMount() {
this.props.fetchCategory(this.props.match.params.id);
if (this.props.match.params.id) {
this.setState({
_id: this.props.match.params.id
});
}
}
handleSubmit = e => {
e.preventDefault();
console.log(this.state);
};
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
render() {
const addingNew = this.props.match.params.id === undefined;
return (
<div className="container">
<h4>{addingNew ? "Add category" : "Edit category"}</h4>
<form onSubmit={this.handleSubmit}>
<div className="input-field">
<input
type="text"
id="name"
defaultValue={this.props.category.name}
onChange={this.handleChange}
/>
<label htmlFor="name">Category name</label>
</div>
<div className="input-field">
<input
type="text"
id="urlKey"
onChange={this.handleChange}
defaultValue={this.props.category.urlKey}
/>
<label htmlFor="urlKey">URL Key</label>
</div>
<button className="btn">{addingNew ? "Add" : "Save"}</button>
</form>
</div>
);
}
}
const mapStateToProps = state => {
return {
category: state.categoryReducer.category
};
};
export default connect(
mapStateToProps,
{ fetchCategory }
)(AddOrEditCategory);
EDIT: Included whole component as requested
You need to replace the 'defaultValue' attribute with 'value' in the inputs.
You are using a controlled vs uncontrolled component. You dont need to use defaultValue.
You can set the initial values on the promise success for fetchCategory
componentDidMount() {
this.props.fetchCategory(this.props.match.params.id).then(response => {
// Set the initial state here
}
}
OR in
componentWillReceiveProps(nextProps) {
// Compare current props with next props to see if there is a change
// in category data received from action fetchCategory and set the initial state
}
React docs
<form onSubmit={this.handleSubmit}>
<div className="input-field">
<input
type="text"
id="name"
onChange={this.handleChange}
value={this.state.name} //<---
/>
<label htmlFor="name">Category name</label>
</div>
<div className="input-field">
<input
type="text"
id="urlKey"
onChange={this.handleChange}
value={this.state.urlKey}
/>
<label htmlFor="urlKey">URL Key</label>
</div>
<button className="btn">{addingNew ? "Add" : "Save"}</button>
</form>

Submitting redux form values

I am new to react and redux technology. now started building an application that contains several redux forms. We want to submit simple form with values.
For ex: login form
Username : text input field
Password: text input field
Submit button
After entering values in fields and click on submit button i want to get the username and password field values in object or json data .. so that I can store it to my server with POST method.
Right now we are using handleSubmit(), but data is not coming as object
1 - The best practice to deal with input values are making them controlled. Which means :
Instead of
<input type='password' />
You do :
<input
type='password'
value={password}
onChange={ event => myInputHandler( event.target.value ) }
/>
The value might come from your state, redux state or as a props etc.
Your handler function differs according to where you store it.
I will give you an example with react state :
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
So whenever someone types, your onChange handler will be called, so that your react state will update with the input ( event.target.value ).
2 - If you need these values when a user submits, then you need to wrap these input fields within a form element and attach a onSubmit handler.
onSubmitHandler( event ){
event.preventDefault()
let password = this.state.password
// use password or other input fields, send to server etc.
}
<form onSubmit={ event => this.onSubmitHandler(event) }>
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
</form>
Hope you get what you need.
If you are using redux to store state then use redux-from then use redux from
import React from 'react'
import {Field, reduxForm} from 'redux-form'
const SimpleForm = props => {
const {handleSubmit, submitting} = props return (
<form onSubmit={handleSubmit(e=>console.log('your form detail here', e))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" placeholder="Last Name" />
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
</div>
</form>
) }
export default reduxForm({ form: 'simple'})(SimpleForm)
Go here for more detail
https://redux-form.com
I put the name of the input as the key that I want to use.
Then each time the input changes I destructure the event passed to the onChange function, and I use the name,value to update the state.
On form submit make sure to use preventDefault(); in order to avoid the page refreshing.
import React, { Component } from 'react'
class FormExample extends Component {
constructor(props){
super(props)
this.state = {
formData: {}
}
}
handleInputChange = ({ target: { name,value } }) => {
this.setState({
formData: {
...this.state.formData,
[name]: value
}
})
}
handleFormSubmit = e => {
e.preventDefault()
// This is your object
console.log(this.state.formData)
}
render() {
return(
<div>
<Form
handleSubmit={this.handleFormSubmit}
handleChange={this.handleInputChange}
/>
</div>
)
}
}
const Form = ({ handleSubmit, handleChange }) => (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} name="username" type="text" placeholder="Username" />
<input onChange={handleChange} name="password" type="password" placeholder="Password" />
<button>Submit</button>
</form>
)
export default FormExample

Resources