ReactJS: Triggering event onBlur - reactjs

I am having child component for input fields which is checking its validation onBlur event.
Child component usage:
<TextInput
id={'lastName'}
label={'Last name'}
required={true}
minChars={3}
maxChars={25}
/>
Child component code:
onBlur(event) {
// logic here
}
render() {
let props = this.props;
return (
<div>
<div className="form-group">
<label htmlFor={props.id}>{props.label}</label>
<input
id={props.id}
type={props.type}
className="form-control"
onBlur={this.onBlur.bind(this)}
/>
<p className="text-danger">{this.error}</p>
</div>
</div>
);
}
This works just fine.
When user submits form from parent component, I would like onBlur to be triggered across all inputs. How could I accomplish this?

In the parent component:
_handleBlur (eventData) {}
render () {
const handleBlur = this._handleBlur.bind(this);
return (
<form>
<ChildComponent onBlur={handleBlur} {...moreProps} />
<ChildComponent onBlur={handleBlur} {...moreProps} />
<ChildComponent onBlur={handleBlur} {...moreProps} />
<button type="submit" onClick={handleBlur}>Submit</button>
</form>
);
}
In the child component:
render () {
const props = this.props;
return (
<div>
<div className="form-group">
<label htmlFor={props.id}>{props.label}</label>
<input
id={props.id}
type={props.type}
className="form-control"
onBlur={props.onBlur}
/>
<p className="text-danger">{this.error}</p>
</div>
</div>
);
}
Based on eventData or other params, you can define which field needs to be blurred. I don't know what exactly needs to happen on blur. In some cases it might be better to split it into a handleBlur and handleBlurAll method.
Hope this helps

Related

onChange not getting called React

I'm trying to debug a react checkbox and the onChange event doesn't ever get called. I have added a console.log to test and this doesn't ever run. Here is the code for the checkbox. What is the issue?
return (
<div className="RampPane">
<div className="RampPane--content">
<p className="RampText">{transaction.merchant} </p>
<b>{moneyFormatter.format(transaction.amount)}</b>
<p className="RampText--hushed RampText--s">
{transaction.employee.firstName} {transaction.employee.lastName} - {transaction.date}
</p>
</div>
<InputCheckbox
id={transaction.id}
checked={approved}
disabled={loading}
onChange={async (newValue) => {
console.log("click")
await consumerSetTransactionApproval({
transactionId: transaction.id,
newValue,
})
setApproved(newValue)
}}
/>
</div>
)
Here is the InputCheckBox Component
return (
<div className="RampInputCheckbox--container" data-testid={inputId}>
<label
className={classNames("RampInputCheckbox--label", {
"RampInputCheckbox--label-checked": checked,
"RampInputCheckbox--label-disabled": disabled,
})}
/>
<input
id={inputId}
type="checkbox"
className="RampInputCheckbox--input"
checked={checked}
disabled={disabled}
onChange={() => onChange(!checked)}
/>
</div>
)
Use this for InputCheckBox Component
return (
<div className="RampInputCheckbox--container" data-testid={inputId}>
<label
className={classNames("RampInputCheckbox--label", {
"RampInputCheckbox--label-checked": checked,
"RampInputCheckbox--label-disabled": disabled,
})}
htmlFor={inputId}
/>
<input
id={inputId}
type="checkbox"
className="RampInputCheckbox--input"
checked={checked}
disabled={disabled}
onChange={() => onChange(!checked)}
/>
</div>
)
This works!
If the InputCheckBox is a custom built react component that renders an html input element try checking that the onChange handler is passed to the root component correctly
IF Not try including the component here to get a better insight

How can I access the value of my inputs in React?

So I have a regular page, I am working with next js. It looks like this:
"use client"
import SubjectInput from "../../../../components/subjectsInput"
export default function Page()
{
let inputs = []
for (let i = 0; i < numberOfInputsGiven; i++) {
inputs.push(<SubjectInput key={i}/>)
}
return(
<>
<form>
<>
{inputs}
</>
<button type="submit">OK</button>
</form>
</>
)
}
I use a component called "SubjectInput", to generate the input fields I need. Now, my question is, how can I access the value of the inputs that are in SubjectInput? Here is what SubjectInput looks like:
export default function SubjectInput(){
return(
<div>
<div>
<label>Name</label>
<input type="text" placeholder="Enter subject's name" required />
</div>
<div>
<label>From</label>
<input type="time" placeholder="Enter subject's starting time" required />
</div>
<div>
<label>To</label>
<input type="time" placeholder="Enter subject's ending time" required />
</div>
</div>
)
}
I would create a component that just holds one label and input, import it into the main page and change the values through props.
Main page
import Input from "./components/Input";
function App() {
return (
<div className="App">
<form>
<Input label="my text" type="text" value="hello" />
<Input label="my number" type="number" value="123" />
<Input type="submit" />
</form>
</div>
);
}
export default App;
Input component
import React from "react";
const Input = (props) => {
return (
<div>
<label>{props.label}</label>
<input type={props.type} value={props.value} />
</div>
);
};
export default Input;

The react app is returning/printing data for one text input but not for other. I have used the exact same blocks of code but nothing seems to work

import React from 'react'
export default class Login extends React.Component {
handleSubmit=(e)=>
{
e.preventDefault();
console.log('you clikked submit')
}
state={
fName:'',
lName:'',
gender:'',
}
These are the functions i am talking about
i am using setState to set the values input from the textfield.
fnameChange = (e) =>{
this.setState({fName:e.target.value})
}
lnameChange = (e) =>{
this.setState({lName:e.target.value})
}
render() {
return (
<div>
<h1>Login</h1>
<form
onSubmit={this.handleSubmit}
className='add-form' autoComplete="off">
<div className='form-control' >
These are the input fields from where i am calling the functions.
both are coded in exact same way.
I am using tags for printing the data to webpage.
I also tried console logging => onChange, the lastName textfield.
But some how onChange set for lastName textfield is getting fired when i enter value in firstName textfield.
<div>
<label >First Name</label>
<input type='text' name='firstName' onChange={this.fnameChange.bind(this)} required maxLength={10}/>
<h1>{this.state.fName}</h1>
</div>
<div>
<label >Last Name</label>
<input type='text' name='lastName' onChanege={this.lnameChange.bind(this)} required maxLength={10}/>
<h1>{this.state.lName}</h1>
</div>
<div>
<label >Email</label>
<input type='text' name='email' required />
<h1>{this.state.fName}</h1>
</div>
</div>
<div className='form-control form-control-check'>
<p><label>Male</label>
<input type='radio' name='gender' value='male' required/></p>
<p><label>Female</label>
<input type='radio' name='gender' value='female'/></p>
<p><label>Other</label>
<input type='radio' name='gender' value='other'/></p>
</div>
<div className='form-control'>
<input type='submit' value='Login'
className='btn btn-block'
/>
</div>
</form>
</div>
)
}
}
<input type='text' name='lastName' onChanege={this.lnameChange.bind(this)} required maxLength={10}/>
onChanege should be onChange
Multiple problems.
You are resetting your state on each onChange.
You had to consider the previous values and override the state like,
fnameChange = (e) => {
this.setState({...this.state, fName: e.target.value });
};
lnameChange = (e) => {
this.setState({...this.state, lName: e.target.value });
};
You don't need to bind as you are using arrow functions.
You can use the value of state to make your inputs a controlled component.
Example: https://stackblitz.com/edit/react-ts-dufrzd?file=Hello.tsx

React Hooks Form not returning values on submit

I want to build a form where I loop over an array of questions and collect the values of radio buttons for a quiz. Later I want to store those values, so I can can perform some calculations on the result, but for now I just want to log the value (1,2,3,4) and the name of the input to the console. As I'm new to React and Hooks, I have tried the following, but the result that is logged is always an epmty object. The desired result should look like this (built in vanilla JS):
https://florestankorp.github.io/D-D-AlignmentTest/
App.tsx
import React from 'react';
import { useForm } from 'react-hook-form';
import { Question } from '../shared/interfaces';
const QUESTIONS: Question[] = [
{
id: 'q201',
question:
'1. Family elders are expressing disapproval of you to the rest of the family. Do you:',
option1: 'Accept the criticism and change your ways?',
option2: 'Seek a compromise with them?',
option3:
'Besmirch the reputation of those expressing disapproval as you ignore their scorn?',
option4: 'Silence them any way you can?',
},
];
export default function App() {
const { register, handleSubmit } = useForm();
const onSubmit = (data: any) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{QUESTIONS.map((question) => (
<Question {...question} />
))}
<input type="submit" />
</form>
);
}
function Question(props: any): any {
return (
<div>
<p className="question">{props.question}</p>
<div>
<input name={props.id} value="1" type="radio" />
<label htmlFor={props.id}>{props.option1}</label>
</div>
<div>
<input name={props.id} value="2" type="radio" />
<label htmlFor={props.id}>{props.option2}</label>
</div>
<div>
<input name={props.id} value="3" type="radio" />
<label htmlFor={props.id}>{props.option3}</label>
</div>
<div>
<input name={props.id} value="4" type="radio" />
<label htmlFor={props.id}>{props.option4}</label>
</div>
</div>
);
}
I see you are using the useForm hook. Looking at the docs, they provide a method called "register" which you use to register each input component with the hook. That needs to be incorporated into your Question component.
I would suggest
Ensure you add a "key" attribute on the Question component when you map the QUESTIONS array
pass register as a prop to Question, and use it as ref={props.register} on every input component.
see below
export default function App() {
const { register, handleSubmit } = useForm();
const onSubmit = (data: any) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{QUESTIONS.map((question) => (
<Question {...question} register={register} key={question.id} /> //<-- notice register and key attribute
))}
<input type="submit" />
</form>
);
}
now you can include this prop in your question component
function Question(props: any): any {
return (
<div>
<p className="question">{props.question}</p>
<div>
<input name={props.id} value="1" type="radio" ref={props.register} /> //<-- note ref={props.register}
<label htmlFor={props.id}>{props.option1}</label>
</div>
<div>
<input name={props.id} value="2" type="radio" ref={props.register} />
<label htmlFor={props.id}>{props.option2}</label>
</div>
<div>
<input name={props.id} value="3" type="radio" ref={props.register} />
<label htmlFor={props.id}>{props.option3}</label>
</div>
<div>
<input name={props.id} value="4" type="radio" ref={props.register} />
<label htmlFor={props.id}>{props.option4}</label>
</div>
</div>
);
}
This should then update the state for the submit event. See this CodeSandbox
EDIT
Added the Answer of #Amit from the comment added below
react-hook-form updated to 7.0.0 from 6.X.X and has breaking changes:
You have to replace all ref={register} with
{...register('value_name')}
Example: Version 6.X.X:
<input ref={register({ required: true })} name="test" />
Version 7.0.X:
<input {...register('test', { required: true })} />

React- onSubmit Function on forms is not working

I'm not sure what i'm doing wrong here. I'm trying to console log when i click on a button on a form element using onSubmit function.
export class Search extends Component {
state = {
text: ''
};
onFormSubmit = e => {
console.log('Working');
e.preventDefault();
};
onChange = e => this.setState({ [e.target.name]: e.target.value });
render() {
return (
<div>
<form onSubmit={this.onFormSubmit} className='form' />
<input
type='text'
onChange={this.onChange}
value={this.state.text}
name='text'
placeholder='Search Users...'
/>
<input
type='submit'
value='Search'
className='btn btn-dark btn-block'
/>
</div>
);
}
}
You are not wrapping your button in form but closing the form itself,
<form onSubmit={this.onFormSubmit} className='form' />
You need to wrap input and button in form like,
<form onSubmit={this.onFormSubmit} className='form'>
<input
type='text'
onChange={this.onChange}
value={this.state.text}
name='text'
placeholder='Search Users...'
/>
<input
type='submit'
value='Search'
className='btn btn-dark btn-block'
/>
</form> //form closing tag

Resources