React radio button requires two clicks to render - javascript

I'm controlling a Radio button on a react form.
The state is updating on change as expected, but the checked value isn't being rerendered on change. Therefore, from a user perspective the button isn't working.
I've replicated this in a codesandbox here https://codesandbox.io/s/eager-hertz-stzgk?file=/src/App.js
Relevant code:
const [selectedRole, setSelectedRole] = useState("staff");
...
const handleRoleChange = (event) => {
event.preventDefault();
setSelectedRole(event.target.value);
};
...
<form>
<label>
Staff
<input
type="radio"
name="role"
value="staff"
checked={selectedRole === "staff"}
onChange={handleRoleChange}
/>
</label>
<label>
Student
<input
type="radio"
name="role"
value="student"
checked={selectedRole === "student"}
onChange={handleRoleChange}
/>
</label>
</form>
Appreciate any help as I'm out of ideas.
Thank you

That is because of event.preventDefault() in 9th line which stops it to change it instantly
Edit 1: 2/5/2022:
you can also refer to: docs

Related

Redirecting form to unique URL in Gatsby?

I am new to Gatsby and I am trying to create a form that goes to a unique URL based on Selection. It needs to go to a third party site for checkout.
The code below works fine on a standard HTML page, but not at all when added to Gatsby.
The errors are;
TypeError: Cannot set property 'onsubmit' of null
}
18 | , myForm = document.getElementById('order-form');
> 19 | myForm.onsubmit = e => {
20 | e.preventDefault()
21 | if (myForm.option.value)
22 | document.location = direction[myForm.option.value]
<form action="" id="order-form">
<label> Quantity 1 <input type="radio" name="option" value="Option1" > </label>
<label> Quantity 2 <input type="radio" name="option" value="Option2" > </label>
<label>Quantity 3 <input type="radio" name="option" value="Option3" > </label>
<button type="submit">submit</button>
</form>
const
direction =
{
Option1: 'https://www.example.com/cart/31852303417409:1',
Option2: 'https://www.example.com/cart/31852303417409:2',
Option3: 'https://www.example.com/cart/31852303417409:3',
}
, myForm = document.getElementById('order-form')
;
myForm.onsubmit=e=>
{
e.preventDefault()
if (myForm.option.value)
document.location = direction[ myForm.option.value ]
}
I appreciate any help I can get. Thanks!
In Gatsby, so in React too, you are creating a virtual DOM instead of attacking the real one, so, it can be considered bad practice to refer directly to the DOM objects such as document to point to any element. In addition, that's why React is so fast because pointing the real DOM has a huge performance effect. You can use useRef hook that recreates the same behavior in the virtual DOM.
Your code should be adapted to:
const orderForm=useRef(null);
const yourSubmitFunction=e=>{
e.preventDefault();
if(orderForm.current.option.value){
document.location = direction[myForm.option.value]
}
}
return <form action="" id="order-form" onSubmit={yourSubmitFunction} ref="orderForm">
<label> Quantity 1 <input type="radio" name="option" value="Option1" > </label>
<label> Quantity 2 <input type="radio" name="option" value="Option2" > </label>
<label>Quantity 3 <input type="radio" name="option" value="Option3" > </label>
<button type="submit">submit</button>
</form>
Let's dive step by step.
It's a good practice to initialize a reference to null to avoid cached values when rehydrating the component.
event (e) it's a default parameter so you can't omit them because a submit function always has it.
As I said, document.getElementById it's a pointer to the real DOM, but with references, orderForm.current has exactly the same object data as document.getElementById so you can keep that condition with a little refactoring.
Finally, I don't know your use-case but, you may want to use a window.location if the navigation is external or use a navigate if you are redirecting the user to any internal page.

How can I get the value of the radio button after click

How will I get the value of the radio button after clicked on the button?
document.getElementById('btnKnop1').addEventListener('click', function(){
var kleuren = document.querySelectorAll('input[type=radio');
for (var i in kleuren) {
kleuren[i].onclick = function(){
document.getElementById('divResult'). innerHTML =
'Gekozen kleur: ' + this.value;
}
}
});
<input type="radio" name="radioGroup" value="rood" checked />Rood</br />
<input type="radio" name="radioGroup" value="blauw" />Blauw</br />
<input type="radio" name="radioGroup" value="geel" />Geel</br />
<input type="radio" name="radioGroup" value="groen" />Groen</br />
<button id="btnKnop1">Check de waarde!</button>
<div id="divResult"></div>
Now it depends on click on the radio button, but I'd to depend on click on the button
The issue seems to be be the inner click event on the radio button. If you change the loop to an if statement checking if it's checked then you can output the value on the button click:
document.getElementById('btnKnop1').addEventListener('click', function(){
var kleuren = document.querySelectorAll('input[type=radio');
for (var i in kleuren) {
if (kleuren[i].checked === true) {
document.getElementById('divResult'). innerHTML =
'Gekozen kleur: ' + kleuren[i].value;
}
}
});
<input type="radio" name="radioGroup" value="rood" checked />Rood</br>
<input type="radio" name="radioGroup" value="blauw" />Blauw</br>
<input type="radio" name="radioGroup" value="geel" />Geel</br>
<input type="radio" name="radioGroup" value="groen" />Groen</br>
<button id="btnKnop1">Check de waarde!</button>
<div id="divResult"></div>
First of all, please consider using english-named variables, it will improve readability by a lot.
Second of all, line
var kleuren = document.querySelectorAll('input[type=radio');
has a typo, it's missing a closing square bracket - ].
To check a checkbox/radio button value you can use checkbox.checked, where checkbox is your DOM object selected by querySelector.
You're basically already doing it. When you click the button, in the click handler for the button, just grab the radio button element using a selector (either class or id), with a "querySelector" call (just like you're doing). Inspect that element for whatever property makes sense (probably "checked").
Something like:
<button onclick="onClick ()">Click Me</button>
...
onClick () {
const kleuren = document.querySelector ( [mySelectorByIDorClass, etc.] );
console.log ( kleuren.checked );
}
See here:
https://www.w3schools.com/jsref/prop_radio_checked.asp
The checked property will tell you whether the element is selected:
if (document.getElementById('id').checked) {
var variable = document.getElementById('id').value;
}

Update form redirection URL depending on radio button value with JS

I try to update a form redirection URL depending on the value of the selected radio button of the form.
For instance,
If button value = 1, then go to mywebsite.com/page-a
or
If button value = 2, then go to mywebsite.com/page-b
You'll find here the code I've done so far (jsfiddle below) :
<label class="labl">
<input type="radio" name="quantite" value="1" checked="checked"/>
<div>
<span class="box"><b>First choice</b></span><br>
</div>
</label>
<label class="labl">
<input type="radio" name="quantite" value="2" />
<div>
<span class="box"><b>Second choice</b></span><br>
</div>
</label>
<label class="labl">
<input type="radio" name="quantite" value="3" />
<div>
<span class="box"><b>Third choice</b></span><br>
</div>
</label>
And JS
$('!selector!').parents("form").attr("action","https://www.mywebsite.com");
$('!selector!').on('change', function(){
var newValue = parseInt($(this).val());
var $form = $(this).parents("form");
switch(newValue){
case 1:
$form.attr("action", "https://www.mywebsite.com/page-a/");
break;
case 2:
$form.attr("action", "https://www.mywebsite.com/page-b/");
break;
case 3:
$form.attr("action", "https://www.mywebsite.com/page-c/");
break;
}
});
https://jsfiddle.net/pcL8vfvn/
But nothing happen when I change the selected button and submit my form.
I think there is a flaw in the JS code.
Thanks for the help !
I'm not fluent in jQuery, but this logs the correct values:
$('input[name="quantite"]').on('change', function()
{
var newValue = parseInt($(this).val());
console.log(JSON.stringify(newValue));
});
It attaches the function to the onchange event of each radio button.
I think I've found the easiest solution by adding this as an attribute the each radio button :
onclick="document.getElementById('my-form').action='https://www.mywebsite.com/page-x';"
It works like a charm !

without an event for a radiobutton or checkbox, how can I set it true or false programmatically

I have a page with radiobuttons and checkboxes; the form has previously been filled out by the user. I need to bring the form back up for them to edit the EXISTING data, which means I have to programmatically check checkboxes and check radio buttons.
If I HAD an event, I could easily change the corresponding control with srcElement, but there is no event in this case. I haven't been able to find a way with document.getElementById('XXX'). ??? to work in any way.
Using Angular 4 if that helps.
Thoughts?
Thanks in advance, :-)
Use data binding. Then you can set the changed value and the checkbox and radio buttons will check/select automatically.
Here is an example:
<label>
<input id="sendCatalogId"
type="checkbox"
[(ngModel)]="sendCatalog"
name="sendCatalog" >
Send me your catalog
</label>
And a radio button:
<label class="radio-inline">
<input type="radio" id="addressType1Id" value="home"
[(ngModel)]="addressType"
name="addressType">Home
</label>
<label class="radio-inline">
<input type="radio" id="addressType1Id" value="work"
[(ngModel)]="addressType"
name="addressType">Work
</label>
<label class="radio-inline">
<input type="radio" id="addressType1Id" value="other"
[(ngModel)]="addressType"
name="addressType">Other
</label>
This in the component class:
...
export class CustomerComponent {
sendCatalog = false;
addressType = "home";
constructor() {
sendCatalog = true;
addressType = "work";
}
}

React-Router Link, how to trigger a click event on a Link from another component

I'm trying to set up a series of React-Router to have navigation within a certain component. I have it set up so the link tags work correctly but I'm trying to style them to look like this:
The styling is set up like this:
<div className="btn-group" data-toggle="buttons">
<label className="btn btn-primary-outline active">
<input type="radio" name="options" id="option1" autocomplete="off" checked />Payments
</label>
<label className="btn btn-primary-outline">
<input type="radio" name="options" id="option2" autocomplete="off" /> Bills
</label>
<label className="btn btn-primary-outline">
<input type="radio" name="options" id="option3" autocomplete="off" /> Charge
</label>
</div>
And the current series of Links looks like this (with no styling):
<ul>
<Link to='/options/option1'>option1</Link>
<Link to='/options/option2'>option2</Link>
<Link to='/options/option3'>option3</Link>
</ul>
The HTML (top) is written in HTML, not JSX, but that's not the issue. I am trying to combine the Link Components into the HTML above so that the options will trigger the functionality of the link tags.
In the React documentation I found this:
For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in componentDidMount(), unsubscribe in componentWillUnmount(), and call setState() when you receive an event. Flux pattern is one of the possible ways to arrange this.
So this gave me the idea of putting the Link tags inside of their respective labels, giving them a style of {{display: 'none'}}, and having the clicks on the radio buttons trigger a click on the respective Link tag. That would ensure all the same functionality happens that we'd expect from the Link tag (pushing to browser history etc).
However, the following is not working:
<label className="btn btn-primary-outline active" onClick={() => document.getElementById('linkToOption1').click() }>
<Link to='/options/option1' id="linkToOption1" style={{display: 'none'}}>Option1</Link>
<input type="radio" name="options" id="option1" autoComplete="off" defaultChecked />Option1
</label>
In the previous example you can see I created an onClick event handler that selects the id of the Link tag and triggers a click.
I was able to solve my problem so I am posting what worked for me. Please answer or comment if there's changes or a better solution.
I wasn't able to trigger a click event on a Link, but I was able to simulate the aspects that I needed.
For this to work I needed the following:
on a click event push to browserHistory to update the route
link the 'active' css class to the current view/URL (I accomplished this through component state)
update the state whenever the url is changed (modified state on window popstate event, and also update the currentView state on component will mount)
This results in the ability for the correct tab to be highlighted when a tab is clicked, when the url is manually changed to a certain route, and when the browsers back / forward buttons are used.
This is all the code in my navmenu file that creates a pretty cool navigation component and works with react-router and browserHistory.
import React, { Component, PropTypes } from 'react'
import { Link, browserHistory } from 'react-router'
class Navmenu extends Component {
constructor(props) {
super(props)
this.state = { currentView: '' }
this.getClasses.bind(this)
}
// in case of url being manually set, figure out correct tab to highlight
// add event listener to update the state whenever the back/forward buttons are used.
componentWillMount() {
this.changeLocation()
window.addEventListener('popstate', this.changeLocation.bind(this))
}
componentWillUnmount() {
window.removeEventListener('popstate', this.changeLocation.bind(this))
}
// update state based on the URL
changeLocation() {
const path = window.location.pathname.split('/')
const currentView = path[path.length - 1]
this.setState({ currentView })
}
// update state and update react-router route
navigateToRoute(route) {
this.setState({ currentView: route })
browserHistory.push(`/options/${route}`)
}
// give correct tab the 'active' bootstrap class
getClasses(link) {
let classes = 'btn btn-primary-outline flex-button'
if (this.state.currentView === link) {
classes += ' active'
}
return classes
}
render() {
return (
<div className="btn-group flex-navbar" data-toggle="buttons">
<label className={this.getClasses('option1')} onClick={() => this.navigateToRoute('option1')}>
<input type="radio" name="options" id="option1" autoComplete="off" defaultChecked />option1
</label>
<label className={this.getClasses('option2')} onClick={() => this.navigateToRoute('option2')}>
<input type="radio" name="options" id="option2" autoComplete="off" /> option2
</label>
<label className={this.getClasses('option3')} onClick={() => this.navigateToRoute('option3')}>
<input type="radio" name="options" id="option2" autoComplete="off" /> option3
</label>
</div>
)
}
}
export default Navmenu

Categories