I'm making a form, and I was in need of a radio input. How do I get the checked radio input in a onSubmit-function, what is the correct way?
This is my code, I myRadioInput-variable to contain either Option A or Option B when I submit:
React.createClass({
handleSubmit: function() {
e.preventDefault();
var myTextInput = this.refs.myTextInput.getDOMNode().value.trim();
var myRadioInput = "How ?";
},
render: function() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref="myTextInput" />
<label>
<span>Option A</span>
<input type="radio" name="myRadioInput" value="Option A"/>
</label>
<label>
<span>Option B</span>
<input type="radio" name="myRadioInput" value="Option B"/>
</label>
<input type="submit" value="Submit this"/>
</form>
)
}
});
If you make sure all your form elements have name attributes, you can extract data from the form onSubmit using form.elements:
handleSubmit: function(e) {
e.preventDefault()
var form = e.target
var myTextInput = form.elements.myTextInput.value
var myRadioInput = form.elements.myRadioInput.value
// ...
}
In modern browsers, form.elements.myRadioInput should be a RadioNodeList which has a .value corresponding to the selected value, but when that's not supported you will get a NodeList or HTMLCollection of nodes which must be iterated over to find the selected value.
I also have a reusable React component - <AutoForm> - which uses a generic implementation of data extraction from form.elements for you. I've used it in the snippet below:
<meta charset="UTF-8">
<script src="http://fb.me/react-0.13.1.js"></script>
<script src="http://fb.me/JSXTransformer-0.13.1.js"></script>
<script src="https://cdn.rawgit.com/insin/react-auto-form/master/dist/react-auto-form.js"></script>
<div id="app"></div>
<script type="text/jsx;harmony=true">void function() { "use strict";
var Example = React.createClass({
getInitialState() {
return {submittedData: null}
},
handleSubmit(e, submittedData) {
e.preventDefault()
this.setState({submittedData})
},
render() {
return <div>
<AutoForm onSubmit={this.handleSubmit}>
<input type="text" name="myTextInput" />
<label>
<span>Option A</span>
<input type="radio" name="myRadioInput" value="Option A"/>
</label>
<label>
<span>Option B</span>
<input type="radio" name="myRadioInput" value="Option B"/>
</label>
<input type="submit" value="Submit this"/>
</AutoForm>
{this.state.submittedData && <pre>
{JSON.stringify(this.state.submittedData, null, 2)}
</pre>}
</div>
}
});
React.render(<Example/>, document.getElementById('app'))
}()</script>
You shouldn't use refs to get access to DOM nodes and inspect their value. Instead you should link the inputs value to a property on the component state.
Here are some examples of how to do it: https://facebook.github.io/react/docs/two-way-binding-helpers.html
{ items.map(item =>
<span id="qn" key={item.qno}>{item.qno}</span>
)}
{ items.map(item =>
<span id="qd" key={item.qno}>{item.question}<br/>
<br/>
<input onClick={this.captureClick} type="radio" value="1" checked={this.state.option === "1"}
onChange={this.handleChange}/>
{ item.options.map(option =>
<span id="op" key={option.option1}>
{option.option1}</span>
)}<br/>
<br/> <input onClick={this.captureClick} type="radio" value="2" checked={this.state.option === "2"}
onChange={this.handleChange} />
{ item.options.map(option =>
<span id="op" key={option.option2}>
{option.option2}</span>
)}<br/><br/>
<input onClick={this.captureClick} type="radio" value="3" checked={this.state.option === "3"}
onChange={this.handleChange} />
{ item.options.map(option =>
<span id="op" key={option.option3}>
{option.option3}</span>
)}<br/><br/>
<input onClick={this.captureClick} type="radio" value="4" checked={this.state.option === "4"}
onChange={this.handleChange} />
{ item.options.map(option =>
<span id="op" key={option.option4}>{option.option4}</span>
)}<br/><br/>
<button type="submit" className="save" onClick={this.onSave}>SAVE</button>
</span>
You can use Radio button's like this also
i use this solution for radio button two way binding with active :
inside render() method:
const items = [
{label: 'one', checked: false},
{label: 'two', checked: true},
{label: 'three', checked: true}
];
items.map((item, index) => (
<div className={`radioItem (item.checked) ? 'active' : ''`}>
<label>
{item.label}
<input type="radio"
name="address"
value={item.label}
onClick={(e)=>{
$('.radioItem').filter('.active').removeClass('active');
$(e.currentTarget).closest('.radioItem').addClass('active');
}}
ref={elm => $(elm).prop('checked', item.checked)}
/>
</label>
</div>
))
Related
I want to display user inputs and render them as new inputs are in. But currently, I can't seem to find a way to store the ratio values of multiple selections. I have tried "bind.(this)" and etc. None worked :(
Here's my code
import React, { Component } from "react";
class Input extends Component {
state = {
nameItems: [],
ageItems: [],
statusItems: [],
nameInput: '',
ageInput: '',
statusInput: ''
}
nameChangeHandler = ({target:{value}}) => this.setState({
nameInput: value
})
ageChangeHandler = ({target:{value}}) => this.setState({
ageInput: value
})
submitHandler = e =>{
e.preventDefault()
this.setState({
nameItems: [...this.state.nameItems, this.state.nameInput],
ageItems: [...this.state.ageItems, this.state.ageInput],
statusItems: [...this.state.statusItems, this.state.statusInput],
nameInput: '',
ageInput: '',
statusInput: ''
})
}
render() {
return (
<div>
<h1>User signup form</h1>
<form onSubmit={this.submitHandler}>
<label for="name">Name:</label><br />
<input type="text" id="name" name="name" value={this.state.nameInput} onChange={this.nameChangeHandler} /><br />
<label for="age">Age:</label><br />
<input type="number" id="age" name="age" value={this.state.ageInput} onChange={this.ageChangeHandler}/><br />
<div class="schoolYear">
<p>Your status:</p>
<input type="radio" id="freshman" name="status" value="freshman" />
<label for="freshman">Freshman</label><br />
<input type="radio" id="css" name="status" value="sophomore" />
<label for="sophomore">Sophomore</label><br />
<input type="radio" id="junior" name="status" value="junior" />
<label for="junior">Junior</label><br />
<input type="radio" id="senior" name="status" value="senior" />
<label for="senior">Senior</label><br />
</div>
<input class="submit" type="submit" value="Submit" />
<ul>
{
this.state.nameItems.map((key) => <li>{key}</li>)
}
{
this.state.ageItems.map((key) => <li>{key}</li>)
}
{
this.state.statusItems.map((key) => <li>{key}</li>)
}
</ul>
</form>
</div>
)
}
}
export default Input;
I have tried using the onChange on each individual option and the whole div but still can seem to obtain the radio value. Also when I tried setting "checked" the whole program seems to end up in a loop.
Just Copied Your code .
First of All , if you want to multiple select radio , don't name it as the same.
<div class="schoolYear">
<p>Your status:</p>
<input type="radio" id="freshman" name="freshman" value="freshman" onChange={(event)=>{setStatus((prev)=>[...prev,event.currentTarget.value])}}/>
<label for="freshman">Freshman</label><br />
<input type="radio" id="css" name="css" value="sophomore" onChange={(event)=>{setStatus((prev)=>[...prev,event.currentTarget.value])}}/>
<label for="sophomore">Sophomore</label><br />
<input type="radio" id="junior" name="junior" value="junior" onChange={(event)=>{setStatus((prev)=>[...prev,event.currentTarget.value])}}/>
<label for="junior">Junior</label><br />
<input type="radio" id="senior" name="senior" value="senior" onChange={(event)=>{setStatus((prev)=>[...prev,event.currentTarget.value])}}/>
<label for="senior">Senior</label><br />
</div>
I need to get the children of the Section block. Namely fields and rabiobuttons. Next, check them for fullness. How to do it. I tried to get through childNodes, children but nothing worked.
In this case, I want to get the context of the section block and check the fields
Such sections, I need to validate section by section and until the previous one is filled, I do not validate the next one.
const formStepTwo = document.getElementById("formStepTwo");
const Section = document.querySelectorAll(".Section");
formStepTwo.addEventListener("change", () => {
//console.log( Section.item(0))
let count = Array.from(Section).forEach((i) => {
let context = i.children;
context.item()
console.log( this.querySelectorAll(".input[type=radio]"))
//console.log(context.forEach());
});
});
<form class="stepTwo-profile" id="formStepTwo">
<p class="stepTwo-profile-title">Демография</p>
<div class="Section">
<label for="age"
>Возраст пациента<input
type="number"
class="stepTwo-profile-item-textAge"
name="age"
min="0"
max="80"
maxlength="2"
id="age"
/></label>
<p class="stepTwo-profile-item-smTitle">Пол</p>
<label for="male">
<input type="radio" name="gender" id="male" value="male" />Мужской
<span class="stepTwo-profile-item-radionbtn"></span
></label>
<label for="female">
<input type="radio" name="gender" id="female" value="female" />Женский
<span class="stepTwo-profile-item-radionbtn"></span>
</label>
</div>
</div>
</form>
You can actually check for input fields by targeting 'label' since they directly wrap over the input tag. Targeting through .Section can get a bit tricky, but is doable.
Another alternative is to directly target input fields using querySelectorAll('input') and then check for their type.
I've added example of both in the code snippet :
const formStepTwo = document.getElementById("formStepTwo");
const labels = document.querySelectorAll("label");
formStepTwo.addEventListener("change", () => {
let count = Array.from(labels).forEach((i) => {
let children = i.children;
Array.from(children).forEach((node) => {
if(node.nodeName.toLowerCase() === 'input') {
switch(node.type) {
case 'number' : validateNumberField(node);
break;
case 'radio' : validateRadio(node);
break;
// add more cases as required
default:
console.log('add default');
}
}
});
});
});
// Can also be done by targeting input directly
const input = document.querySelectorAll('input');
formStepTwo.addEventListener("change", () => {
Array.from(input).forEach((node) => {
if(node.nodeName.toLowerCase() === 'input') {
switch(node.type) {
case 'number' : validateNumberField(node);
break;
case 'radio' : validateRadio(node);
break;
// add more cases as required
default:
console.log('add default');
}
}
});
});
function validateNumberField(node) {
console.log('validating number field');
// add your validation
}
function validateRadio(node) {
console.log('validation radio button');
// add your validation for radio
}
<form class="stepTwo-profile" id="formStepTwo">
<p class="stepTwo-profile-title">Демография</p>
<div class="Section">
<label for="age"
>Возраст пациента<input
type="number"
class="stepTwo-profile-item-textAge"
name="age"
min="0"
max="80"
maxlength="2"
id="age"
/></label>
<p class="stepTwo-profile-item-smTitle">Пол</p>
<label for="male">
<input type="radio" name="gender" id="male" value="male" />Мужской
<span class="stepTwo-profile-item-radionbtn"></span
></label>
<label for="female">
<input type="radio" name="gender" id="female" value="female" />Женский
<span class="stepTwo-profile-item-radionbtn"></span>
</label>
</div>
</div>
</form>
Maybe this helps you:
const formStepTwo = document.getElementById("formStepTwo");
const sections = [...document.querySelectorAll(".Section")];
formStepTwo.addEventListener("input", () => {
sections.forEach(s=>{
const inps=[...s.querySelectorAll("input,select")].filter(el=>el.type!=="radio"||el.checked);
console.log(inps.map(el=>el.name+":"+el.value))
});
});
<form class="stepTwo-profile" id="formStepTwo">
<p class="stepTwo-profile-title">Демография</p>
<div class="Section">
<label for="age"
>Возраст пациента<input
type="number"
class="stepTwo-profile-item-textAge"
name="age"
min="0"
max="80"
maxlength="2"
id="age"
/></label>
<p class="stepTwo-profile-item-smTitle">Пол</p>
<label for="male">
<input type="radio" name="gender" id="male" value="male" />Мужской
<span class="stepTwo-profile-item-radionbtn"></span
></label>
<label for="female">
<input type="radio" name="gender" id="female" value="female" />Женский
<span class="stepTwo-profile-item-radionbtn"></span>
</label>
</div>
</form>
The script goes through all sections (currently there is only one ;-)) and collects all input values. (Radio buttons are only picked up if they are "checked".)
i have the following data below.anytime i map through it into the form element and i try to click the radio button for the next question the first question which is checked becomes uncheck and vice-versa if i go back to the first question. and i would love to get the values of the two questions answered.
class Exam extends Component {
constructor(props) {
super(props)
this.state = {
question : [
{
"id": 1,
"question": "what is the name of a boy",
"A": "tope",
"B": "tosin",
"C": "tayo",
"D": "tolu",
"Answer" : "A",
"chosen": ""
},
{
"id": 2,
"question": "what is the name of a girl",
"A": "Kanyin",
"B": "Kanmi",
"C": "Keji",
"D": "Kaffy",
"Answer" : "A",
"chosen": ""
}
]
}
this.markPaper = this.markPaper.bind(this)
this.handleChange = this.handleChange.bind(this)
}
markPaper = (event) => {
event.preventDefault();
console.log(this.state.chosen)
alert(this.state.chosen)
}
handleChange = event => {
event.preventDefault()
console.log(event.target.value)
this.setState({
chosen: event.target.value
})
}
render() {
return (
<form>
{
this.state.question.map((set) => {
return(
<div key={set.id}>
<p>{set.question}</p>
<input type="radio" name="chosen" value="A" onChange={this.handleChange} />{set.A}
<input type="radio" name="chosen" value="B" onChange={this.handleChange} />{set.B}
<input type="radio" name="chosen" value="C" onChange={this.handleChange} />{set.C}
<input type="radio" name="chosen" value="D" onChange={this.handleChange} />{set.D}
</div>
)
})
}
</form>
)
}
}
You need to check whether the option is selected or not for each question.
<input type="radio" name="chosen" value="A" onChange={this.handleChange}
checked={set.chosen === set.A} />{set.A}
<input type="radio" name="chosen" value="B" onChange={this.handleChange}
checked={set.chosen === set.B} />{set.B}
<input type="radio" name="chosen" value="C" onChange={this.handleChange}
checked={set.chosen === set.C} />{set.C}
<input type="radio" name="chosen" value="D" onChange={this.handleChange}
checked={set.chosen === set.D} />{set.D}
The issue is with the name...
instead of
<input type="radio" name="chosen" value="A" onChange={this.handleChange} />
use :
<input type="radio" name={set.id} value="A" onChange={this.handleChange} />
the issue is because all radio button have same name, hence they behave together as single radio input, rather than being separate set, each radio input has name chosen....
setting name of input to set.id allows you to have separate input...
I have found another issue in your code, after you select the radio button the state does not update... you should check on that...
The radio inputs are grouped by your attribute name, e.g.:
<p>Select ur favorite language:</p>
<div>
<input type="radio" id="js" name="fav-language" value="js"
checked>
<label for="js">JavaScript</label>
</div>
<div>
<input type="radio" id="php" name="fav-language" value="php">
<label for="php">PHP</label>
</div>
<div>
<input type="radio" id="python" name="fav-language" value="python">
<label for="python">Python</label>
</div>
<p>Select ur favorite space tab:</p>
<div>
<input type="radio" id="tab-0" name="fav-space" value="0"
checked>
<label for="tab-0">0 spaces</label>
</div>
<div>
<input type="radio" id="php" name="fav-space" value="php">
<label for="tab-2">2 spaces</label>
</div>
<div>
<input type="radio" id="python" name="fav-space" value="python">
<label for="tab-4">4 spaces</label>
</div>
If you run above code, you will to note that the check boxes in questions "Select ur favorite language" and "Select ur favorite space tab" do not interfere with each other.
I change your code to good operation, check here.
Also check the real documentation to more details.
I believe this is what you are after...
I am changing the way you are handling your state and other little things...
see the problem is that your state is { chosen : answer } , as you can see the state stores only one answer, and it does not know which set it is.
Your state should be like:
{chosen:{ question1: answer1,question2: answer2...} }
now let's implement this..
the handleChange event should be:
handleChange = setId => {
return (event)=>{
console.log(event.target.value);
this.setState({
chosen: {...this.state.chosen,[setId]:event.target.value}
});
}
}
now we have covered the major part..
update your input element :
<input type="radio" name="chosen" value="A" onChange={this.handleChange} />
with this:
<input type="radio" name={set.id} value="A" checked={this.state.chosen[set.id] == "A"} onChange={this.handleChange(set.id)}/>
Complete Code Comming...
OR You Can Follow This Method
It will work very well but many minor changes...
function RadioInput(props){
return(
<>
<input type="radio" name={props.set.id} value={props.value} check={props.value == props.set.chosen} onChange={props.handleChange}/> {props.set.choices[props.value]}
</>
)
}
class App extends Component {
constructor(props) {
super(props)
this.state = {
questions : [
{
"id": 1,
"question": "what is the name of a boy",
"choices":{
"A": "tope",
"B": "tosin",
"C": "tayo",
"D": "tolu",
},
"answer" : "A",
"chosen": ""
},
{
"id": 2,
"question": "what is the name of a girl",
"choices":{
"A": "kaneyi",
"B": "maneyi",
"C": "tayosa",
"D": "toluli",
},
"answer" : "A",
"chosen": ""
},
]
}
}
handleChange = setId => {
return (event)=>{
console.log(event.target.value);
this.setState({
questions: this.state.questions.map((question)=>{
if(question.id == setId){
question.chosen = event.target.value
return question
}else{
return question
}
})
});
}
}
render() {
return (
<form>
{
this.state.questions.map((set) => {
return(
<div key={set.id}>
<p>{set.question} ?</p>
<RadioInput handleChange={this.handleChange(set.id).bind(this)} set={set} value={"A"} />
<RadioInput handleChange={this.handleChange(set.id).bind(this)} set={set} value={"B"} />
<RadioInput handleChange={this.handleChange(set.id).bind(this)} set={set} value={"C"} />
<RadioInput handleChange={this.handleChange(set.id).bind(this)} set={set} value={"D"} />
</div>
)
})
}
<hr/>
<div>
State:
{JSON.stringify(this.state.questions)}
</div>
</form>
)
}
}
render(<App />, document.getElementById('root'));
Preview Page...
Preview
I am new to react and I am trying to pass the values inside a form to the parent component and then display the values in other child component.
I tried using states and props but it seems like I am missing something. It tells me that you are trying to use props on undefined value. I am not able to figure out where. I tried googling and did some search. nothing works as of now.
Here is my code:
Parent :
constructor(props) {
super(props);
this.state = {
name: "",
age:"",
gender:""
};
}
changeValue(name,age,gender) {
this.setState({
name: name,
age:age,
gender:gender
});
}
render() {
return (
<div>
<FormView changeValue={this.changeValue.bind(this)}/>
<DisplayView name={this.state.name} age= {this.state.age} gender= {this.state.gender}/>
</div>
);
}
Child 1 :
constructor(props) {
super(props);
}
handleChange(e){
this.props.changeValue(e.target.name.value,e.target.age.value,e.target.gender.value);
}
render() {
return <form>
<label>
Name:
<input type="text" name="name" />
</label>
<label>
Age:
<input type="number" name="age" />
</label>
<label>
Gender:
<select name="gender" >
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</label>
<input type="button" value="Submit" onClick = {this.handleChange.bind(this)} />
</form>
}
Child2 :
render(){
return (
<div>
<p>{this.props.name}</p>
<p>{this.props.age}</p>
<p>{this.props.gender}</p>
</div>
)
}
I am expecting to display the form values of child1 in child2.
I am getting an undefined value error.
You component works fine if we define an onSubmit listener and handler for the form. We also need to call event.preventDefault() to stop the page from refreshing, that way the values actually get passed up to parent component when you call this.props.changeValue()
See codesandbox: https://codesandbox.io/s/gallant-ellis-76bdv
import React from "react";
class FormView extends React.Component {
constructor(props) {
super(props);
}
handleChange(e){
e.preventDefault()
this.props.changeValue(
e.target.name.value,
e.target.age.value,
e.target.gender.value
);
};
render() {
return (
<form onSubmit={this.handleChange.bind(this)}>
<label>
Name:
<input type="text" name="name" />
</label>
<label>
Age:
<input type="number" name="age" />
</label>
<label>
Gender:
<select name="gender">
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default FormView;
To get an element in React you can use refs on each input or one on the form https://reactjs.org/docs/refs-and-the-dom.html
constructor(props) {
super(props);
}
handleChange(e){
console.log(this.name.value, this.age.value, this.gender.value);
this.props.changeValue(this.name.value, this.age.value, this.gender.value);
}
setName = (name) => {
this.name = name;
}
setAge = (age) => {
this.age = age;
}
setGender = (gender) => {
this.gender = gender;
}
render() {
return <form>
<label>
Name:
<input type="text" ref={this.setName} name="name" />
</label>
<label>
Age:
<input type="number" ref={this.setAge} name="age" />
</label>
<label>
Gender:
<select ref={this.setGender} name="gender" >
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</label>
<input type="button" value="Submit" onClick = {this.handleChange.bind(this)} />
I wonder is it okay to keep some UI state as instance variables(this) rather than in react state object. For example making controlled inputs sometimes becomes tedious, wouldn't it be better to keep it like:
import React from 'react';
export default class extends React.Component {
selectedCheckboxes = new Set();
searchInput = '';
radioButton = undefined;
onCheckboxChange = ({target: {value}}) => {
if (this.selectedCheckboxes.has(value)) {
this.selectedCheckboxes.delete(value);
} else {
this.selectedCheckboxes.add(value);
}
};
submit = e => {
e.preventDefault();
const searchInput = this.searchInput;
const checkboxes = [...this.selectedCheckboxes];
const radioButton = this.radioButton;
console.log(searchInput, checkboxes, radioButton);
};
render() {
return (
<form className="Example" onSubmit={this.submit}>
<div className="checkboxes">
<input type="checkbox" value="a" onChange={this.onCheckboxChange}/>
<input type="checkbox" value="b" onChange={this.onCheckboxChange}/>
<input type="checkbox" value="c" onChange={this.onCheckboxChange}/>
</div>
<div className="search">
<input type="text" onChange={e => this.searchInput = e.target.value}/>
</div>
<div className="radio-buttons">
<input type="radio"
name="radio"
value="1"
onChange={e => this.radioButton = e.target.value}/>
<input type="radio"
name="radio"
value="2"
onChange={e => this.radioButton = e.target.value}/>
<input type="radio"
name="radio"
value="3"
onChange={e => this.radioButton = e.target.value}/>
</div>
<button type="submit">submit</button>
</form>
)
}
}
I know downside of this approach is that component is not notified when value of this-variables has changed so component will not update. But on the other side sometimes it is not neccessary (like in my example) and it can boost performance as it dont triger re-render, and avoids reconcilation.
Reference