How to store ratio values in React? - javascript

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>

Related

Script with querySelector works only once for class

The script below works fine for the first div with the .inp class, it doesn't work for the second block with the same class. I broke my head trying to figure out why this is happening and how to make it work, while NOT ADDING new classes or IDs to the second div.
document.querySelector("input").focus();
document.querySelector(".inp").addEventListener("input", function({ target, data }){
// Exclude non-numeric characters (if a value has been entered)
data && ( target.value = data.replace(/[^0-9]/g,'') );
const hasValue = target.value !== "";
const hasSibling = target.nextElementSibling;
const hasSiblingInput = hasSibling && target.nextElementSibling.nodeName === "INPUT";
if ( hasValue && hasSiblingInput ){
target.nextElementSibling.focus();
}
});
.inp input {
display: inline-block;
width: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="inp">
<input type="text" name="digit1" />
<input type="text" name="digit2" />
<input type="text" name="digit3" />
<input type="text" name="digit4" />
<input type="text" name="digit5" />
</div>
<div class="inp">
<input type="text" name="digit1" />
<input type="text" name="digit2" />
<input type="text" name="digit3" />
<input type="text" name="digit4" />
<input type="text" name="digit5" />
</div>
Using (document|element).querySelector will give the first element which matches the query.
You can user (document|element).querySelectorAll instead in this scenario.
document.querySelector("input").focus();
document.querySelectorAll(".inp").forEach(element=>element.addEventListener("input", function({ target, data }){
// Exclude non-numeric characters (if a value has been entered)
data && ( target.value = data.replace(/[^0-9]/g,'') );
const hasValue = target.value !== "";
const hasSibling = target.nextElementSibling;
const hasSiblingInput = hasSibling && target.nextElementSibling.nodeName === "INPUT";
if ( hasValue && hasSiblingInput ){
target.nextElementSibling.focus();
}
}))
.inp input {
display: inline-block;
width: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="inp">
<input type="text" name="digit1" />
<input type="text" name="digit2" />
<input type="text" name="digit3" />
<input type="text" name="digit4" />
<input type="text" name="digit5" />
</div>
<div class="inp">
<input type="text" name="digit1" />
<input type="text" name="digit2" />
<input type="text" name="digit3" />
<input type="text" name="digit4" />
<input type="text" name="digit5" />
</div>
Here you go:
document.querySelector("input").focus();
document.querySelectorAll(".inp").forEach(inp => {
inp.addEventListener("input", function({ target, data }){
// Exclude non-numeric characters (if a value has been entered)
data && ( target.value = data.replace(/[^0-9]/g,'') );
const hasValue = target.value !== "";
const hasSibling = target.nextElementSibling;
const hasSiblingInput = hasSibling && target.nextElementSibling.nodeName === "INPUT";
if ( hasValue && hasSiblingInput ){
target.nextElementSibling.focus();
}
});
})
.inp input {
display: inline-block;
width: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="inp">
<input type="text" name="digit1" />
<input type="text" name="digit2" />
<input type="text" name="digit3" />
<input type="text" name="digit4" />
<input type="text" name="digit5" />
</div>
<div class="inp">
<input type="text" name="digit1" />
<input type="text" name="digit2" />
<input type="text" name="digit3" />
<input type="text" name="digit4" />
<input type="text" name="digit5" />
</div>
As Pointy mentioned querySelector() method can only be used to access a single element while querySelectorAll() method can be used to access all elements which match with a specified CSS selector.
.querySelector will work only for the first element it finds, you should use .querySelectorAll instead. It will return a node list of all selectors with your class.
Then you can iterate with a loop through all of them and add the event listener.

How to get fields via children or childnodes

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".)

how to fix hook to set state in React JS?

I am trying to have a user set a function variable with an input number. I have a form they enter a number into, which needs to set the col const up top.
So far, i am using a simple hook, and col is being set (i console logged it), but its not producing the desired array. Im thinking its something getting messed up in the toggling at the bottom of the code.
function DataFrame(){
const [toggle, setToggle] = React.useState(false);
const [col, setCol] = useState(0)
var element = <li class="element"/>
var row = 3
var arr = []
var i
for (i = 0; i<row; i++){
arr.push(element)
}
const Element = () => <li className="element" />;
console.log(col)
return (
<div>
<div >
<div style={{fontFamily:'PressStart2P',opacity:'45%', width:'360px',
position:'absolute',left:'36px', top: '160px',color:'rgb(143, 0, 145)'}}>
</div>
<div >
<h1 class="dfHeader" style={{left:'30px'}}>
DataFrames :<br></br></h1>
<h1 class='dfHeader2'style={{top:'150px',left:'30px'}}>
constructor</h1>
<div class="codeBorder" style={{scrollbarColor:'#6a00ff'}}>
<div class="textbox" style={{width:'180px'}}>
<p class="instructions"></p>
<p class="instructions2"></p>
<p class="instructions3">
<form class="codeForm">
<label>
enter dimensions:
<input type="number" name="dimension" onKeyUp=
{e => setCol(e.target.value)} />
</label>
<input class='goButton' type="submit" value="run" />
</form>
<br/><br/></p>
<p class="instructions3">
<form class="codeForm">
<label>
input code:
<input type="number" name="dimension" />
</label>
<input class='goButton' type="submit" value="run" />
</form></p>
<p class="instructions3">
<form class="codeForm">
<label>
input code:
<input type="number" name="dimension" />
</label>
<input class='goButton' type="submit" value="run" />
</form></p>
<p class="instructions3">
<form class="codeForm">
<label>
input code:
<input type="number" name="dimension" />
</label>
<input class='goButton' type="submit" value="run" />
</form> </p>
</div>
</div>
<div class="btnConsole">
<button class="dfButton" onClick={()=>setToggle( (prev) => (!prev) )}>
</button>
</div>
</div>
<div class="monitor"style={{}}>
<div class="superScreen">
<div class="screenDiv" >
<div id="subScreen" class="subScreen">
{[...Array(col).keys()].map(ul => (
<ul key={ul}>
{toggle &&
[...Array(row).keys()].map(
li => <Element key={li} />)}
</ul>
))}
</div>
</div>
</div>
</div>
<br/>
</div>
</div>
)
}
export default DataFrame;
ReactDOM.render(<DataFrame />, document.getElementById('root'));
Any help is appreciated as always!
onKeyUp={e => setCol(e.target.value)}
this is the cause of your problem. e.target.value is a string, you are setting col equal to a string. Consequently, [...Array(col).keys()] gives you an array of length 1.
const col = '5';
console.log([...Array(col).keys()]);
Change
onKeyUp={e => setCol(e.target.value)}
to
onKeyUp={e => setCol(Number(e.target.value))}

Show/Hide Combobox Dropdown with pure Javascript

I have a user control in asp.net that outputs markup similar to the following:
<div id="combobox1">
<div id="combobox1_text"><span>combobox 1</span></div>
<div id="combobox1_ddl">
<input type="checkbox" id="combobox1_$1" />
<label for="combobox1_$1">Item 1</label>
<br />
<input type="checkbox" id="combobox1_$2" />
<label for="combobox1_$2">Item 2</label>
<br />
<input type="checkbox" id="combobox1_$3" />
<label for="combobox1_$3">Item 3</label>
<br />
<input type="checkbox" id="combobox1_$4" />
<label for="combobox1_$4">Item 4</label>
<br />
<input type="checkbox" id="combobox1_$5" />
<label for="combobox1_$5">Item 5</label>
<br />
</div>
</div>
A javascript file accompanying this control has the following class (minimal code to reproduce the problem only):
ComboBox = function(cb) {
var pnlContainer = document.getElementById(cb);
var pnlComboBox = document.getElementById(cb + '_text');
var pnlDropdownList = document.getElementById(cb + '_ddl');
var isCollapsed = true;
var collapseDropdown = function() {
if (!isCollapsed) {
isCollapsed = true;
pnlDropdownList.style.display = 'none';
//-- some more custom handling code follows here --
}
};
pnlComboBox.onclick = function() {
isCollapsed = !isCollapsed;
pnlDropdownList.style.display = (isCollapsed) ? 'none' : 'block';
};
pnlContainer.onclick = function(event) {
event.stopPropagation();
};
document.addEventListener('click', function() {
collapseDropdown();
}, false);
}
And finally, on my page I create an instance of the class like this:
cb1 = new ComboBox('combobox1');
All this works fine until there is only one instance of this control. It collapses correctly whenever anything or anywhere outside the control is clicked, just as expected.
The Problem:
The problem happens when there are more than one instances of this control on the page. If one of the comboboxes is open, and user clicks on another instance of my combobox, the previous one doesn't collapse.
JsFiddle for minimal code to reproduce the problem can be found here:
https://jsfiddle.net/x8qjo79f/
I know it is happening because of event.stopPropagation() call, but don't know what to do for this.
Edit the document onclick event listener to capture the event (so it is executed before the bubbling phase) and collapse when its target is outside your combobox.
ComboBox = function(cb) {
var pnlContainer = document.getElementById(cb);
var pnlComboBox = document.getElementById(cb + '_text');
var pnlDropdownList = document.getElementById(cb + '_ddl');
var isCollapsed = true;
var collapseDropdown = function() {
if (!isCollapsed) {
isCollapsed = true;
pnlDropdownList.style.display = 'none';
//-- some more custom handling code follows here --
}
};
pnlComboBox.onclick = function() {
isCollapsed = !isCollapsed;
pnlDropdownList.style.display = (isCollapsed) ? 'none' : 'block';
};
pnlContainer.onclick = function(event) {
event.stopPropagation();
};
// Edit: Capture click event
document.addEventListener('click', function(event) {
if (!pnlContainer.contains(event.target)) collapseDropdown();
}, true);
}
cb1 = new ComboBox('combobox1');
cb2 = new ComboBox('combobox2');
#combobox1,
#combobox2 {
border: 1px solid black;
cursor: default;
width: 200px;
font-family: verdana;
font-size: 10pt;
}
#combobox1_text,
#combobox2_text {
padding: 2px;
}
#combobox1_ddl,
#combobox2_ddl {
border-top: 1px solid black;
display: none;
}
<div id="combobox1">
<div id="combobox1_text"><span>combobox 1</span></div>
<div id="combobox1_ddl">
<input type="checkbox" id="combobox1_$1" />
<label for="combobox1_$1">Item 1</label>
<br />
<input type="checkbox" id="combobox1_$2" />
<label for="combobox1_$2">Item 2</label>
<br />
<input type="checkbox" id="combobox1_$3" />
<label for="combobox1_$3">Item 3</label>
<br />
<input type="checkbox" id="combobox1_$4" />
<label for="combobox1_$4">Item 4</label>
<br />
<input type="checkbox" id="combobox1_$5" />
<label for="combobox1_$5">Item 5</label>
<br />
</div>
</div>
<br />
<input type="text" />
<br />
<input type="button" />
<br />
<input type="checkbox" />
<br />
<span>some random text in the document.. <br />blah. blah.. blah..</span>
<br />
<br />
<br />
<div id="combobox2">
<div id="combobox2_text"><span>combobox 2</span></div>
<div id="combobox2_ddl">
<input type="checkbox" id="combobox2_$1" />
<label for="combobox2_$1">Item 1</label>
<br />
<input type="checkbox" id="combobox2_$2" />
<label for="combobox2_$2">Item 2</label>
<br />
<input type="checkbox" id="combobox2_$3" />
<label for="combobox2_$3">Item 3</label>
<br />
<input type="checkbox" id="combobox2_$4" />
<label for="combobox2_$4">Item 4</label>
<br />
<input type="checkbox" id="combobox2_$5" />
<label for="combobox2_$5">Item 5</label>
<br />
</div>
</div>
You could allow the event propagation in pnlContainer.onclick but remember that the ComboBox was clicked. Inside the document click event handler, you would test if the ComboBox is the clicked one, and allow to collapse only if it is not.
The changes to the Javascript code could look like this:
ComboBox = function(cb) {
var isClicked = false;
...
pnlContainer.onclick = function(event) {
isClicked = true;
};
document.addEventListener('click', function() {
if (isClicked) {
isClicked = false;
}
else {
collapseDropdown();
}
}, false);
}

How do I use radio buttons in React?

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>
))

Categories

Resources