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);
})
}
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 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;
I need to be able to have radion buttons or checkboxes to show / hide content if its checked. There will be more radio buttons and checkboxes to show content in the same form, so to distinguish them from each other, it could be based on the name attribute.
So far i can show the hidden fields when i check the radio buttons, but i want one to cancel out the other, but only if it has the same name attribute (something else can also work).
Is there a react genius who can figure this out? I would be forever in your debt :)
class PartnerRoute extends Component {
constructor(props) {
super(props)
this.state = {
showOneTimeFee: '',
showSubscription: ''
};
}
toggleOneTimeFee = () => {
const currentState = this.state.showOneTimeFee;
this.setState({
showOneTimeFee: !currentState
})
}
toggleSubscription = () => {
const currentState = this.state.showSubscription;
this.setState({
showSubscription: !currentState
})
}
render() {
return (
<div className="partner-route">
<ContentContainer>
<div className="form--create-event">
<form>
<h3>Event information</h3>
<GridContainer columnCount="one">
<CustomInput type="text" placeholder="Event name" />
</GridContainer>
<GridContainer columnCount="one">
<CustomTextarea type="text" placeholder="Event description" />
</GridContainer>
<h3>Event date</h3>
<GridContainer columnCount="three">
<CustomInput type="text" placeholder="Day" />
<CustomInput type="text" placeholder="Month" />
<CustomInput type="text" placeholder="Year" />
</GridContainer>
<h3>Payment</h3>
<GridContainer columnCount="one">
<CustomRadio
type="radio"
name="payment"
id="rb1"
value="1"
label="Free, no payment needed"
/>
<CustomRadio
type="radio"
name="payment"
id="rb2"
value="2"
label="1 time fee"
onChange={this.toggleOneTimeFee}
/>
{this.state.showOneTimeFee &&
<div className="hidden-field">
<CustomInput type="text" placeholder="Price" />
</div>
}
<CustomRadio
type="radio"
name="payment"
id="rb3"
value="3"
label="Subscription"
onChange={this.toggleSubscription}
/>
{this.state.showSubscription &&
<div className="hidden-field">
<CustomInput type="text" placeholder="Price" />
</div>
}
</GridContainer>
</form>
</div>
</ContentContainer>
</div>
)
}
}
export default PartnerRoute
Please check this example where I used setState with prevState that is important and also I used changeHandler for all three radio. Moreover, to run this code in my side I changed all Custom input with generic input for ex CustomInput to input. Please revert this your side.
import React, {Component} from "react";
export default class PartnerRoute extends Component {
constructor(props) {
super(props);
this.state = {
showOneTimeFee: false,
showSubscription: false
};
}
handleChange = (event) => {
if (event.target.value == 2) // One Time Fee
this.setState(prevState => {
return {
showOneTimeFee: !prevState.showOneTimeFee,
showSubscription: false
};
});
else if (event.target.value == 3) // Subscription
this.setState(prevState => {
return {
showOneTimeFee: false,
showSubscription: !prevState.showSubscription
};
});
else // Free, no payment needed
this.setState({
showOneTimeFee: false,
showSubscription: false
});
};
render() {
return (
<div className="partner-route">
<div>
<div className="form--create-event">
<form>
<h3>Event information</h3>
<div>
<input type="text" placeholder="Event name"/>
</div>
<div>
<input type="text" multiline="true" placeholder="Event description"/>
</div>
<h3>Event date</h3>
<div>
<input type="text" placeholder="Day"/>
<input type="text" placeholder="Month"/>
<input type="text" placeholder="Year"/>
</div>
<h3>Payment</h3>
<div>
<input type="radio" name="payment" id="rb1" value="1" label="Free, no payment needed"
onChange={this.handleChange}/>
<label htmlFor="rb1">Free, no payment needed</label><br/>
<input type="radio" name="payment" id="rb2" value="2" label="1 time fee"
onChange={this.handleChange}/>
<label htmlFor="rb2">1 time fee</label><br/>
{this.state.showOneTimeFee &&
<div className="hidden-field">
<input type="text" placeholder="One Time Price"/>
</div>
}
<input type="radio" name="payment" id="rb3" value="3" label="Subscription"
onChange={this.handleChange}/>
<label htmlFor="rb3">Subscription</label><br/>
{this.state.showSubscription &&
<div className="hidden-field">
<input type="text" placeholder="Subscription Price"/>
</div>
}
</div>
</form>
</div>
</div>
</div>
)
}
}
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,
}
});
};
I'm having difficulty understanding how to handle radio buttons in forms with other types of inputs in React. I'm working from an example that incorporates string type input fields and another for pure radio buttons, but not sure how to get them to play nice together. The text field inputs work fine, but I can't get the radio button feature to work.
The basic theory behind the radio button of the React portion of this form is the checkbox for each option is set when a user clicks on a button and the checked value for that particular button is set to true via a logic check, while the other radio buttons are set to false.
I'm not sure how to integrate the handling of the input fields with the radio buttons.
Any guidance on this would be great!
Here's my form jsx:
class Project_form extends React.Component {
handleChange(e) {
const name = e.target.name;
const obj = {};
obj[name] = e.target.value;
this.props.onUserInput(obj);
}
handleOptionChange(e) {
const name = e.target.id;
const obj = {};
obj[name] = e.target.checked;
this.props.onChangeInput(obj);
}
handleSubmit(e) {
e.preventDefault();
this.props.onFormSubmit();
}
render() {
return (
<form onSubmit={(event) => this.handleSubmit(event)} >
<div className="form-group">
<input
id="project_name"
className="form-control"
type="text"
name="project_name"
placeholder="Enter Your Project Name"
value={this.props.project_name}
onChange={(event) => this.handleChange(event)} />
</div>
<div className="form-group">
<input
id="project_zipcode"
className="form-control"
type="text"
name="project_zipcode"
placeholder="Zipcode"
value={this.props.project_zipcode}
onChange={(event) => this.handleChange(event)} />
</div>
<div className="form-group">
<label>How Soon Do You Want this Project Started?</label>
<div className="radio">
<p><input type="radio"
value="1-2 Weeks"
name="project_timeframe"
id="project_timeframe_1-2_weeks"
checked={this.props.project_timeframe === 'ASAP'}
onChange={(event) => this.handleOptionChange(event)} />
<label>As Soon As Possible</label></p>
<p><input type="radio"
value="2-4 Weeks"
name="project_timeframe"
id="project_timeframe_2-4_weeks"
checked={this.props.project_timeframe === '2-4 Weeks'}
onChange={(event) => this.handleOptionChange(event)} />
<label>2-4 Weeks</label></p>
<p><input type="radio"
value="4-6 Weeks"
name="project_timeframe"
id="project_timeframe_4-6_weeks"
checked={this.props.project_timeframe === '4-6 Weeks'}
onChange={(event) => this.handleOptionChange(event)} />
<label>4-6 Weeks</label></p>
<p><input type="radio"
value="More Than 6 Weeks"
name="project_timeframe"
id="project_timeframe_more_than_6_weeks"
checked={this.props.project_timeframe === 'More Than 6 Weeks'}
onChange={(event) => this.handleOptionChange(event)} />
<label>More Than 6 Weeks</label></p>
</div>
</div>
<div className="form-group">
<input
type="submit"
value="Create Project"
className="btn btn-primary btn-lg"
/>
</div>
</form>
)
}
}
Here's my main component, which sets the state of the app.
class Projects extends React.Component {
constructor(props) {
super(props)
this.state = {
projects: this.props.projects,
project_name: '',
project_zipcode: '',
selectedTimeframeOption: 'ASAP'
}
}
handleUserInput(obj) {
this.setState(obj);
}
handleChangeInput(obj) {
this.setState({
selectedOption: obj.target.value
});
}
handleFormSubmit() {
const project = {
name: this.state.project_name,
zipcode: this.state.project_zipcode,
timeframe: this.state.project_timeframe
};
$.post('/projects',
{project: project})
.done((data) => {
this.addNewProject(data);
});
}
addNewProject(project){
const projects = update(this.state.projects, { $push: [project]});
this.setState({
projects: projects.sort(function(a,b){
return new Date(a['updated_at']) - new Date(b['updated_at']);
})
});
}
render() {
return (
<div>
<h2>Start a New Project</h2>
<a href="/projects/new/"
className="btn btn-large btn-success">Create a New Project</a>
{/* <%= link_to "Create a New Project", new_project_path, class: "btn btn-large btn-success" %> */}
<Project_form
project_name={this.state.project_name}
project_zipcode={this.state.project_zipcode}
project_timeframe={this.state.selectedTimeframeOption}
onUserInput={(obj) => this.handleUserInput(obj)}
onFormSubmit={() => this.handleFormSubmit()} />
{/* <% if #current_user.projects.any? %> */}
<div className="col-md-12">
<h3>Existing Projects</h3>
<div className="table-responsive">
<Project_list projects={this.state.projects} />
</div>
</div>
</div>
)
}
}
Ok, figured it out. Had to play around with getting the event object into the stateful component.
My form file now has this event handler added:
handleOptionChange(e) {
const option = e.target.name;
const obj = {};
obj[option] = e.target.value;
this.props.onUserInput(obj);
}
Then this.props.onUserInput(obj); gets called by the existing method in the Project.jsx file and I got rid of the handleChangeInput method.
handleUserInput(obj) {
this.setState(obj);
}
The state then flows down to the Project_form Component here:
<Project_form
project_name={this.state.project_name}
project_zipcode={this.state.project_zipcode}
project_timeframe={this.state.project_timeframe}
onUserInput={(obj) => this.handleUserInput(obj)}
onFormSubmit={() => this.handleFormSubmit()} />