I read about using a single handler for multiple input fields. When I'm trying to use that approach -> using event.target.value, I am getting just the first letter of what I entered in the input. Can anyone please help me on what I am doing wrong.
class AddContactForm extends Component {
constructor(props) {
super(props);
this.name = "";
this.email = ""
this.phone = "";
}
componentDidUpdate() {
console.log("updated");
}
componentWillUnmount() {
console.log("unmounted");
}
componentWillMount() {
console.log("mounted");
}
handleOnChange(event) {
[event.target.name] = event.target.value;
console.log(event)
console.log(event.target.name);
console.log(event.target.value);
}
addContact() {
console.log("add");
this.props.addContactHandler({
name: this.name,
email: this.email,
phone: this.phone
});
}
render() {
return (
<React.Fragment>
<div className="mx-auto">
<div class="mb-3 row">
<label for="username" class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name='name' id="username" onChange={this.handleOnChange.bind(this)} />
</div>
</div>
<div class="mb-3 row">
<label for="mobileNumber" class="col-sm-2 col-form-label">Mobile Number</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="phone" id="mobileNumber" onChange={this.handleOnChange.bind(this)} />
</div>
</div>
<div class="mb-3 row">
<label for="emailId" class="col-sm-2 col-form-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="emailId" name="email" onChange={this.handleOnChange.bind(this)} />
</div>
</div>
<button className="btn btn-primary w-25" onClick={this.addContact.bind(this)}>Add</button>
</div>
</React.Fragment>
)
}
}
export default AddContactForm;
inside handle on change, the value of [event.target.name] always shows whatever was my first input alphabet. for If I am writong abcd ing input, ikt'll keep showing me a .
Where am I going wrong ?
The issue is with the first line of code in this function.
handleOnChange(event) {
[event.target.name] = event.target.value;
console.log(event)
console.log(event.target.name);
console.log(event.target.value);
}
That changes the HTML Input element name's first letter to the first letter of the input value you have typed.
Add with the following log
handleOnChange = (event) => {
[event.target.name] = event.target.value;
console.log(event);
console.log(event.target);
console.log(event.target.name);
console.log(event.target.value);
};
Solution
To change the class variable dynamically,
instead of
[event.target.name] = event.target.value;
use
this[event.target.name] = event.target.value;
You haven't set the state properly in both constructor and handleChange functions.
Try this
import React, { Component } from "react";
class AddContactForm extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
phone: ""
};
}
componentDidUpdate() {
console.log("updated");
}
componentWillUnmount() {
console.log("unmounted");
}
componentWillMount() {
console.log("mounted");
}
handleOnChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
addContact() {
console.log("add");
console.log(this.state);
// this.props.addContactHandler(this.state);
}
render() {
return (
<React.Fragment>
<div className="mx-auto">
<div class="mb-3 row">
<label for="username" class="col-sm-2 col-form-label">
Name
</label>
<div class="col-sm-10">
<input
type="text"
class="form-control"
name="name"
id="username"
onChange={this.handleOnChange.bind(this)}
/>
</div>
</div>
<div class="mb-3 row">
<label for="mobileNumber" class="col-sm-2 col-form-label">
Mobile Number
</label>
<div class="col-sm-10">
<input
type="text"
class="form-control"
name="phone"
id="mobileNumber"
onChange={this.handleOnChange.bind(this)}
/>
</div>
</div>
<div class="mb-3 row">
<label for="emailId" class="col-sm-2 col-form-label">
Email
</label>
<div class="col-sm-10">
<input
type="email"
class="form-control"
id="emailId"
name="email"
onChange={this.handleOnChange.bind(this)}
/>
</div>
</div>
<button
className="btn btn-primary w-25"
onClick={this.addContact.bind(this)}
>
Add
</button>
</div>
</React.Fragment>
);
}
}
export default AddContactForm;
Check console logs
Code sandbox URL => https://codesandbox.io/s/friendly-feather-jcj99?file=/src/App.js:0-2241
you should render this component for this work can use the state and set state ...
class AddContactForm extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
phone: ""
}
}
componentDidUpdate() {
console.log("updated");
}
componentWillUnmount() {
console.log("unmounted");
}
componentWillMount() {
console.log("mounted");
}
handleOnChange(event) {
this.setState({ [event.target.name]: event.target.value })
console.log(event)
console.log(event.target.name);
console.log(event.target.value);
}
addContact() {
console.log("add");
this.props.addContactHandler(this.state);
}
render() {
return (
<React.Fragment>
<div className="mx-auto">
<div class="mb-3 row">
<label for="username" class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name='name' id="username" onChange={this.handleOnChange.bind(this)} />
</div>
</div>
<div class="mb-3 row">
<label for="mobileNumber" class="col-sm-2 col-form-label">Mobile Number</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="phone" id="mobileNumber" onChange={this.handleOnChange.bind(this)} />
</div>
</div>
<div class="mb-3 row">
<label for="emailId" class="col-sm-2 col-form-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="emailId" name="email" onChange={this.handleOnChange.bind(this)} />
</div>
</div>
<button className="btn btn-primary w-25" onClick={this.addContact.bind(this)}>Add</button>
</div>
</React.Fragment>
)
}
}
export default AddContactForm;
If you want use a generic input change handler for all inputs you can get the name and value from event.target. Then create an object from each of them like {name]: value} to pass to this.setState.
handleOnChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value
});
}
class AddContactForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
phone: ""
};
}
handleOnChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value
});
};
render() {
return (
<React.Fragment>
<label>
Name
<input
type="text"
name="name"
onChange={this.handleOnChange}
value={this.state.name}
/>
</label>
<label>
Mobile Number
<input
type="text"
name="phone"
onChange={this.handleOnChange}
value={this.state.phone}
/>
</label>
<label>
Email
<input
type="email"
name="email"
onChange={this.handleOnChange}
value={this.state.email}
/>
</label>
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</React.Fragment>
);
}
}
export default AddContactForm;
If all of your fields are identical, you can even dynamically render them by mapping over the keys of the state object:
class AddContactForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
phone: ""
};
}
handleOnChange = (event) => {
const { name, value } = event.target;
this.setState({
[name]: value
});
};
render() {
return (
<React.Fragment>
{Object.keys(this.state).map((key) => (
<label>
{key}
<input
type="text"
name={key}
onChange={this.handleOnChange}
value={this.state[key]}
/>
</label>
))}
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</React.Fragment>
);
}
}
export default AddContactForm;
Related
I'm creating a simple controlled component form in react. When I console log event.target.name on onChange event it logs fine but when I setState using computed property name of the object in javascript it gives me an error TypeError: Cannot read properties of null (reading 'name')
This never happened before and I've created many working projects where I created the form similar way. Could you please explain why all of sudden these issues occurring to me?
import "./Contact.css";
import React from "react";
const Contact = () => {
const [contactFormValues, setContactFormValues] = React.useState({
fName: "",
lName: "",
email: "",
phone: "",
message: "",
});
const handleChange = (event) => {
setContactFormValues((prevValues) => ({
...prevValues,
[event.target.name]: event.target.value, // Here, this line gives me error
}));
};
const handleSubmit = async (event) => {
event.preventDefault();
console.log(contactFormValues);
}
return (
<>
<div className="contact-form">
<div className="contact-container">
<div className="left-section">
<div className="title">
<h1>Write Us</h1>
</div>
<div className="row">
<div className="contact-sub-row">
<label className="contact-label">First Name</label>
<input
className="contact-input"
type="text"
name="fName"
onChange={handleChange}
value={contactFormValues.fName}
required
/>
</div>
<div className="contact-sub-row">
<label className="contact-label">Last Name</label>
<input
className="contact-input"
type="text"
name="lName"
onChange={handleChange}
// value={contactFormValues.lName}
required
/>
</div>
</div>
<div className="contact-sub-row">
<label className="contact-label">Email</label>
<input
className="contact-input is-success"
type="email"
name="email"
onChange={handleChange}
// value={contactFormValues.email}
required
/>
</div>
<div className="contact-sub-row">
<label className="contact-label">Phone</label>
<input
className="contact-input"
type="tel"
placeholder="1-123-456-7890"
maxlength="20"
name="phone"
onChange={handleChange}
value={contactFormValues.phone}
required
/>
</div>
</div>
<div className="right-section">
<div className="your-message">
<label className="contact-label">Message</label>
<textarea
className="contact-textarea"
name="message"
placeholder="Write text here..."
onChange={handleChange}
value={contactFormValues.message}
required
></textarea>
</div>
<div className="contact-btns">
<button className="submit-btn" onClick={handleSubmit}>SEND MESSAGE</button>
</div>
</div>
</div>
</div>
</>
);
};
export default Contact;
Wrap the inputs in a form tag element.
and try this:
const handleChange = (event) => {
const { name, value } = event.target;
setContactFormValues({ ...contactFormValues, [name]: value });
}
I've done this in our very last project.
I need to add div with three text box, and this div need to be added again and again when add branch button is clicked, Like wise how to do it and get value from it ?
my code:
<div className="form-group">
<label>Store Address</label>
<input type="text"
value={this.state.input.address1}
onChange={this.handleChange}
className="form-control code" name="address1" placeholder="Pincode" />
<span className="form-text" id="errtext">{this.state.errors.address1}</span>
</div>
<div className="form-group">
<div className="row">
<div className="col">
<input type="text" className="form-control code"
value={this.state.input.address2}
onChange={this.handleChange}
name="address2" placeholder="address" />
<span className="form-text" id="errtext">{this.state.errors.address2}</span>
</div>
<div className="col-md-auto">
<p style={{margin:"5px"}}>and</p>
</div>
<div className="col">
<SimpleModal className="form-control" mapFunctionHere={this.mapFunctionHere} />
</div>
</div>
</div>
<div className="form-group">
<input type="text"
className="form-control code"
value={this.state.MapAddr}
onChange={this.handleChange}
name="address3" placeholder="address" readOnly />
<span className="form-text" id="errtext">{this.state.errors.address3}</span>
</div>
It is the div code which to be added multiple times when i click :
<input type="button" className="addbranch" onClick={this.appendDiv} value="Add Branch" />
when add branch is clicked once the above div should appear once, if button is clicked twice then it should appear twice, I need to do like the above and validate the field and get values, how to do it ?
You could use a counter in your state which increases every time, when you click the button until the limit is reached.
import React, { Component } from 'react'
export default class App extends Component {
state = {
counter: 0,
values: [
{ address1: { value: '', error: ''}, address2: { value: '', error: '' }, address3: { value: '', error: '' } }
]
}
handleChangeInput = (counter, key, value) => {
const newValues = [...this.state.values]
newValues[counter][key].value = value
this.setState({ values: newValues })
}
renderBranch = counter => {
const { values } = this.state
return (
<>
<div className="form-group">
<label>Store Address</label>
<input type="text"
value={values[counter].address1.value}
onChange={event => this.handleChangeInput(counter, 'address1', event.target.value)}
className="form-control code"
name="address1"
placeholder="Pincode"
/>
<span className="form-text" id="errtext">
{values[counter].address1.error}
</span>
</div>
<div className="form-group">
<div className="row">
<div className="col">
<input type="text" className="form-control code"
value={values[counter].address2.value}
onChange={event => this.handleChangeInput(counter, 'address2', event.target.value)}
name="address2"
placeholder="address" />
<span className="form-text" id="errtext">
{values[counter].address2.error}
</span>
</div>
</div>
<div className="col-md-auto">
<p style={{margin:"5px"}}>and</p>
<div className="col">
<SimpleModal className="form-control" mapFunctionHere={this.mapFunctionHere}/>
</div>
</div>
</div>
<div className="form-group">
<input type="text"
className="form-control code"
value={values[counter].address3.value}
onChange={event => this.handleChangeInput(counter, 'address2', event.target.value)}
name="address3"
placeholder="address"
readOnly
/>
<span className="form-text" id="errtext">
{values[counter].address3.error}
</span>
</div>
</>
)
}
renderBranches = () => {
const { counter } = this.state
const result = []
for (let i = 0; i <= counter; i++) {
result.push(this.renderBranch(i))
}
return result
}
appendDiv = () => {
this.setState({
counter: this.state.counter + 1,
values: [
...this.state.values,
{ address1: { value: '', error: ''}, address2: { value: '', error: '' }, address3: { value: '', error: '' } }
]
})
}
render = () => {
return (
<>
{this.renderBranches()}
<input type="button" className="addbranch" onClick={this.appendDiv} value="Add Branch" />
</>
)
}
}
I am working on a quiz app project to learn to react. I came across a situation where I need to store incorrect options in a quiz question in an array. And later pass over the information to the database.
This is an example JSON format.
{
incorrect_answers:["Jeff Bezos","Satya Nadela","Bill Gates"] }
The incorrect answer is an array and the value needs to be inputted through separate text boxes for each incorrect option like this.
option input form
The part where I am stuck is appending them to the array here is my attempt.
export default class CreateQuiz extends Component{
constructor(props){
super(props);
this.onChangedIncorrectAnswer=this.onChangedIncorrectAnswer.bind(this);
this.onSubmit=this.onSubmit.bind(this);
this.state={
incorrect_answers:[]
}
}
onChangedIncorrectAnswer(e){
const option=e.target.value
this.setState({
incorrect_answers:[...this.state.incorrect_answers,option]
});
}
onSubmit(e){
e.preventDefault();
const quiz = {
incorrect_answers:this.state.incorrect_answers
}
console.log(quiz);
axios.post("http://localhost:3000/quizes",quiz)
.then(res=>console.log(res.data));
window.location='/quiz-list';
}
render(){
return (
<div>
<h3>Create New Quiz</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Incorrect Option 1</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[0]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 2</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[1]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 3</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[2]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<input type="submit" value="Submit Quiz" className="btn btn-primary"/>
</div>
</form>
</div>
)
}
}
But the form was not working as expected. When I enter content for the first option in the "Option 1" text box only the first character is stored remaining in "Option 2" and so on.
try this, this would work!!
export default class CreateQuiz extends Component {
constructor(props) {
super(props);
this.onChangedCorrectAnswer = this.onChangedCorrectAnswer.bind(this);
this.onChangedIncorrectAnswer = this.onChangedIncorrectAnswer.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
category: "",
correct_answer: "",
difficulty: "",
type: "",
question: "",
incorrect_answers: ["", "", ""]
};
}
onChangedCorrectAnswer(e) {
this.setState({
correct_answer: e.target.value
});
}
onChangedIncorrectAnswer(e, index) {
const option = e.target.value;
const { incorrect_answers } = this.state;
incorrect_answers[index] = option;
this.setState({
incorrect_answers
});
}
onSubmit(e) {
e.preventDefault();
const quiz = {
category: this.state.category,
correct_answer: this.state.correct_answer,
incorrect_answers: this.state.incorrect_answers,
difficulty: this.state.difficulty,
type: this.state.type,
question: this.state.question
};
console.log(quiz);
axios
.post("http://localhost:3000/quizes", quiz)
.then((res) => console.log(res.data));
window.location = "/quiz-list";
}
render() {
return (
<div>
<h3>Create New Quiz</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Correct Answer</label>
<input
type="text"
required
className="form-control"
value={this.state.correct_answer}
onChange={this.onChangedCorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 1</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[0]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 0)}
/>
</div>
<div className="form-group">
<label>Incorrect Option 2</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[1]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 1)}
/>
</div>
<div className="form-group">
<label>Incorrect Option 3</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[2]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 2)}
/>
</div>
<div className="form-group">
<input
type="submit"
value="Submit Quiz"
className="btn btn-primary"
/>
</div>
</form>
</div>
);
}
}
Your array state is considered as one state only
Why don't you create state on the go when user do any change in the input.
create a state object like
this.state = {incorrect_answers: {}}
In your onChangedIncorrectAnswer
onChangedIncorrectAnswer(e){
const option=e.target.value;
const stateName = e.target.name;
this.setState({
incorrect_answers: {...this.state.incorrect_answers, [stateName]: option }
});
}
use your form element as add name as unique which will be used as state
<div className="form-group">
<label>Incorrect Option 1</label>
<input name="incorrect_answers_0" type="text" required className="form-control" value={this.state.incorrect_answers[incorrect_answers_0]}
onChange={this.onChangedIncorrectAnswer} />
</div>
use that object while saving
onSubmit(e){
let yourIncorrectAnswers = Object.values(this.state.incorrect_answers);
})
}
New to react so I apologize if the solution obvious. Working on a registration form that should create a new account on submit using ajax. I know that I'm supposed to use onChange to gather the information is submitted. After seeing a number of examples I am still unable to get my code to work.
I know that the ajax call for POST works because I put in information myself on vscode to test if on submit it will create which it did. I am having issues with the transition from onChange to my submit form. Hope that was clear. Thank you
I've tried creating a onChange function for my registration template. I am unable to get the results that I've been hoping for
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
payload: {
firstName: "",
lastName: "",
email: "",
password: "",
passwordConfirm: ""
}
};
}
handleChange = event => {
let name = event.target.name;
let value = event.target.value;
this.setState({
[name]: value,
[name]: value,
[name]: value,
[name]: value,
[name]: value
});
};
onClickHandler = evt => {
evt.preventDefault();
let payload = this.state;
console.log(payload);
debugger;
registerService
.register(payload)
.then(this.onActionSuccess)
.catch(this.onActionError);
};
onActionSuccess = response => {
console.log(response);
};
onActionError = errResponse => {
console.log(errResponse);
};
<!-- -->
render() {
return (
<main role="main">
<div className="container">
<h1 id="title" align="center">
Register User
</h1>
</div>
<div className="container">
<div className="col-sm-4 col-sm offset-4">
<form className="form">
<div className="form-group">
<label htmlFor="this.state.firstName">First Name</label>
<input
placeholder="First Name"
type="text"
id="this.state.firstName"
className="form-control"
name="firstName"
value={this.state.firstName}
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="this.state.lastName">Last Name</label>
<input
placeholder="last Name"
type="text"
id="this.state. lastName"
className="form-control"
value={this.state.lastName}
onChange={this.handleChange}
/>
<div className="form-group">
<label htmlFor="register-email">Email</label>
<input
placeholder="Enter Email"
type="text"
className="form-control"
id="register-email"
value={this.state.email}
onChange={this.handleChange}
/>
</div>
</div>
<div className="form-group">
<label htmlFor="register-password">Password</label>
<input
placeholder="Password"
type="password"
id="register-password"
`enter code here`className="form-control"
value={this.state.password}
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="register-passwordConfirm">
Confirm Password
</label>
<input
placeholder="Confirm Password"
type="password"
id="register-passwordConfirm"
className="form-control"
value={this.state.passwordConfirm}
onChange={this.handleChange}
/>
</div>
<button onClick={this.onClickHandler} className="btn btn-
primary">
Submit Form
</button>
I am expecting to create a new profile when clicking submit via POST ajax call
Your handleChange function should be
handleChange = event => {
let { name, value } = event.target;
this.setState({
[name]: value,
});
};
You always call your handleChange once at a time. Every time you change something on the input, the function gets different name and different value, which is suffice to add/update the your state.
And I noticed that you also have payload object in state. Modify the state like
this.state = {
firstname: '',
....
}
If you really want to use like
this.state = {
payload: {
firstName: '',
....
}
};
Your onChange function should look like,
handleChange = event => {
let { name, value } = event.target;
this.setState({
payload: {
...this.state.payload, // don't forget to copy all the other values
[name]: value,
}
});
};
Im new to reactJS. Im wondering why my code below doesnt work. Everything works except disabling my NEXT button when text fields are empty. My expectation is that after i fill out ALL the textboxes, the NEXT button will be enabled.
class Registration extends React.Component {
constructor (props) {
super (props);
this.state = {
selectedGender: null,
errors: [],
initComplete: false
}
this._handleSubmit = this._handleSubmit.bind(this);
this._handleInputMobileOnChange =
this._handleInputMobileOnChange.bind(this);
this.clearError = this.clearError.bind(this);
}
clearError () {
this.setState({ errors: [] });
}
_handleInputMobileOnChange (e) {
e.preventDefault();
this.clearError();
e.target.value = utils.removeNonNumbers(e.target.value);
//this.setState({value: e.target.value})
}
change(e){
if("" != e.target.value){
this.button.disabled = false;
}
else{
this.button.disabled = true;
}
}
render() {
return (
<div className="container-fluid">
<form onSubmit={this._handleSubmit}>
<div className="form-group has-danger">
<label htmlFor="input-MobileNum">number *</label>
<input ref={(ref) => this.inputMobile = ref} type="tel" className={'form-control ' } id="input-MobileNum" onChange={()=>{ this._handleInputMobileOnChange; this.change.bind(this)}} defaultValue=""/>
</div>
<div className="form-group has-danger">
<label htmlFor="input-Email">Email address *</label>
<input ref={(ref) => this.inputEmail = ref} type="email" className={'form-control '} id="input-Email" defaultValue="" onChange={()=>{ this.clearError; this.change.bind(this)}}/>
</div>
<div className="form-group has-danger">
<label htmlFor="input-Invitation">Invitation code</label>
<input ref={(ref) => this.inputInvitation = ref} type="text" className={'form-control '} id="input-Invitation" defaultValue="" onChange={()=>{ this.clearError; this.change.bind(this)}}/>
</div>
<div className="form-group cta">
//NEXT BUTTON
<button type="submit" className="btn btn-primary" ref={(button) => this.button=button}>Next</button>
</div>
</form>
</div>
)
}
THANKS!!!
I updated my code to this. And i tested it case by case. Only mobile works, the email and invitation code dont work for some reason.
class Registration extends React.Component {
constructor (props) {
super (props);
this.state = {
selectedGender: null,
errors: [],
initComplete: false
}
this._handleSubmit = this._handleSubmit.bind(this);
this._handleInputMobileOnChange =
this._handleInputMobileOnChange.bind(this);
this._handleInputEmailOnChange =
this._handleInputEmailOnChange.bind(this);
this._handleInputInvitationOnChange =
this._handleInputInvitationOnChange.bind(this);
this.clearError = this.clearError.bind(this);
}
clearError () {
this.setState({ errors: [] });
}
disable(){
let disable = true;
if (this.state.inputMobile || this.state.inputEmail || this.state.inputInvitation) { //I tried && operator, still only mobile works
disable = false;
}
return disable;
}
_handleInputMobileOnChange (e) {
e.preventDefault();
this.clearError();
e.target.value = utils.removeNonNumbers(e.target.value);
this.setState({inputMobile: e.target.value})
}
_handleInputEmailOnChange(e){
e.preventDefault();
this.clearError();
e.target.value = utils.removeNonNumbers(e.target.value);
this.setState({inputEmail: e.target.value})
}
_handleInputInvitationOnChange(e){
e.preventDefault();
this.clearError();
e.target.value = utils.removeNonNumbers(e.target.value);
this.setState({inputInvitation: e.target.value})
}
change(e){
if("" != e.target.value){
this.button.disabled = false;
}
else{
this.button.disabled = true;
}
}
render() {
return (
<div className="container-fluid">
<form onSubmit={this._handleSubmit}>
<div className="form-group has-danger">
<label htmlFor="input-MobileNum">number *</label>
<input ref={(ref) => this.inputMobile = ref} type="tel" className={'form-control ' } id="input-MobileNum" onChange={this._handleInputMobileOnChange}} defaultValue=""/>
</div>
<div className="form-group has-danger">
<label htmlFor="input-Email">Email address *</label>
<input ref={(ref) => this.inputEmail = ref} type="email" className={'form-control '} id="input-Email" defaultValue="" onChange={this._handleInputEmailOnChange}/>
</div>
<div className="form-group has-danger">
<label htmlFor="input-Invitation">Invitation code</label>
<input ref={(ref) => this.inputInvitation = ref} type="text" className={'form-control '} id="input-Invitation" defaultValue="" onChange={this._handleInputInvitationOnChange}/>
</div>
<div className="form-group cta">
//NEXT BUTTON
<button type="submit" className="btn btn-primary" disabled={this.disable()}>Next</button>
</div>
</form>
</div>
)
}
Nvm. I was being stupid. The code above works! :)))
You should consider using controlled input elements rather than uncontrolled. This lets react manage the values of your input elements which makes things a bit easier.
First of all start by adding the initial values of each input element to to your constructor. You probably just want empty strings here ("").
Then, add a change event listener for each input element and create a function for each. Each such function should then check what the value for the other elements are, as well as its own, and then enable or disable the button.
Demo:
class Registration extends React.Component {
constructor (props) {
super(props);
this.state = {
selectedGender: null,
errors: [],
initComplete: false,
buttonIsDisabled: true,
numberValue: "",
emailValue: "",
codeValue: "",
}
this.changeNumber = this.changeNumber.bind(this);
this.changeEmail = this.changeEmail.bind(this)
this.changeCode = this.changeCode.bind(this);
}
changeNumber = (e) => {
let s = true;
if(this.state.emailValue.length && this.state.codeValue.length && e.target.value.length) {
s = false;
}
let val = e.target.value;
//let val = utils.removeNonNumbers(e.target.value);
this.setState({numberValue: val, buttonIsDisabled: s, errors: []});
}
changeEmail = (e) => {
let s = true;
if(this.state.numberValue.length && this.state.codeValue.length && e.target.value.length) {
s = false;
}
this.setState({emailValue: e.target.value, buttonIsDisabled: s, errors: []});
}
changeCode = (e) => {
let s = true;
if(this.state.numberValue.length && this.state.emailValue.length && e.target.value.length) {
s = false;
}
this.setState({codeValue: e.target.value, buttonIsDisabled: s, errors: []});
}
render() {
return (
<div className="container-fluid">
<form onSubmit={this._handleSubmit}>
<div className="form-group has-danger">
<label htmlFor="input-MobileNum">number *</label>
<input type="tel" className={'form-control ' } id="input-MobileNum" onChange={this.changeNumber} />
</div>
<div className="form-group has-danger">
<label htmlFor="input-Email">Email address *</label>
<input type="email" className={'form-control '} id="input-Email" onChange={this.changeEmail} />
</div>
<div className="form-group has-danger">
<label htmlFor="input-Invitation">Invitation code</label>
<input type="text" className={'form-control '} id="input-Invitation" onChange={this.changeCode} />
</div>
<div className="form-group cta">
<button type="submit" className="btn btn-primary" disabled={this.state.buttonIsDisabled} ref={(button) => this.button=button}>Next</button>
</div>
</form>
</div>
)
}}
ReactDOM.render(<Registration />, document.getElementById("myApp"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>
Keep a state disabled and then on change function check whether all inputs have value , then set the state disabled to false like below snippet
class Registration extends React.Component {
constructor (props) {
super (props);
this.state = {
selectedGender: null,
errors: [],
initComplete: false,
disabled: true
}
this._handleSubmit = this._handleSubmit.bind(this);
this._handleInputMobileOnChange =
this._handleInputMobileOnChange.bind(this);
this.clearError = this.clearError.bind(this);
}
clearError () {
this.setState({ errors: [] });
}
_handleInputMobileOnChange (e) {
e.preventDefault();
this.clearError();
e.target.value = utils.removeNonNumbers(e.target.value);
//this.setState({value: e.target.value})
}
change = () => {
if(this.inputMobile !== '' && this.inputEmail !== '' && this.inputInvitation != '' ) {
this.setState({disabled: false});
}
}
render() {
return (
<div className="container-fluid">
<form onSubmit={this._handleSubmit}>
<div className="form-group has-danger">
<label htmlFor="input-MobileNum">number *</label>
<input ref={(ref) => this.inputMobile = ref} type="tel" className={'form-control ' } id="input-MobileNum" onChange={()=>{ this._handleInputMobileOnChange; this.change.bind(this)}} defaultValue=""/>
</div>
<div className="form-group has-danger">
<label htmlFor="input-Email">Email address *</label>
<input ref={(ref) => this.inputEmail = ref} type="email" className={'form-control '} id="input-Email" defaultValue="" onChange={()=>{ this.clearError; this.change.bind(this)}}/>
</div>
<div className="form-group has-danger">
<label htmlFor="input-Invitation">Invitation code</label>
<input ref={(ref) => this.inputInvitation = ref} type="text" className={'form-control '} id="input-Invitation" defaultValue="" onChange={()=>{ this.clearError; this.change.bind(this)}}/>
</div>
<div className="form-group cta">
//NEXT BUTTON
<button type="submit" className="btn btn-primary" ref={(button) => this.button=button} disabled={this.state.disabled}>Next</button>
</div>
</form>
</div>
)
}