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
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>
please i want to add some values into an array i have as property in my data structure but i wasn't getting it right. pls i need help. bellow is my code.
const Question1 = document.querySelector('.qestion1').textContent;
const Option1 = document.querySelectorAll('input[name="option1"]');
const Question2 = document.querySelector('.qestion2').textContent;
const Option2 = document.querySelectorAll('input[name="option2"]');
const Question3 = document.querySelector('.qestion3').textContent;
const Option3 = document.querySelectorAll('input[name="option3"]');
const Question4 = document.querySelector('.qestion4').textContent;
const Option4 = document.querySelectorAll('input[name="option4"]');
const btn = document.querySelector('.btn');
const questions = {
question1: Question1,
correctAns: 'javaScript',
question2: Question2,
correctAns: 'CSS',
question3: Question3,
correctAns: 'Python',
question4: Question4,
correctAns: 'Html',
choosenAnsers: [],
getAns(Option) {
Option.forEach(function (opt1) {
opt1.addEventListener('click', function (e) {
const chosenAns = e.target.value;
this.choosenAnsers.push(chosenAns);
});
});
},
};
console.log(questions.question1);
questions.getAns(Option1);
here is my Html
<p class="qestion1">Q1: What is your favorite programming language</p><br />
<input type="radio" name="option1" value="javaScript" id="A1" />
<label for="A1"> A: javaScript</label><br />
<input type="radio" name="option1" value="Python" id="B1" />
<label for="B1"> B: Python</label><br />
<input type="radio" name="option1" value="Rust" id="C1" />
<label for="C1"> C: Rust</label><br />
<input type="radio" name="option1" value="C++" id="D1" />
<label for="D1"> D: C++</label><br />
and there is the error am getting
Uncaught TypeError: Cannot read properties of undefined (reading 'push')
at HTMLInputElement. (questionScript.js:42:28)
As I`ve seen in you examples your JavaScript and your HTML has a lot of typos, and would not work.
The questions is this snippet is an array, that can be used to have more questions in it, and although I did`nt make the HTML write itself, this should give a concept of how it should work.
const questions = [
{
question: "Q1: What is your favorite programming language",
name: 'question1',
options: [
'JavaScript',
'Python',
'Rust',
'C++'
],
correct: 'JavaScript',
isCorrect: function () {
var radios = document.getElementsByName('question1');
for (let i = 0, length = radios.length; i < length; i++) {
if (radios[i].checked && radios[i].value == this.correct) {
return true;
}
}
return false;
}
},
];
function confirmChoices() {
for (let i = 0; i < questions.length; i++) {
console.log(questions[i].isCorrect());
}
}
<p class="qestion1">Q1: What is your favorite programming language</p>
<br />
<input type="radio" name="question1" value="JavaScript" id="A1" />
<label for="A1"> A: JavaScript</label><br />
<input type="radio" name="question1" value="Python" id="B1" />
<label for="B1"> B: Python</label><br />
<input type="radio" name="question1" value="Rust" id="C1" />
<label for="C1"> C: Rust</label><br />
<input type="radio" name="question1" value="C++" id="D1" />
<label for="D1"> D: C++</label><br />
<button onclick="confirmChoices()">Confirm</button>
the value of this inside of an event listener is going to be the HTML element that is the event's currentTarget, so basically whatever you attached the event listener to. this will not be the questions const as you seem to expect.
A few more things:
you have multiple object properties all trying to use the same name correctAns, which will not work. answers has a 'w' in it.
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
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>
))