Conditional rendering in React not working after onClick event - javascript

I was trying to conditionally show/hide a set of input fields based on a button click event. If the button was clicked, the value of showExtraDetails div will be toggled between true and false.
Here's what I've tried:
state = {
ItemName: '',
ItemPrice:'',
ItemDate: '',
ItemPlace: '',
ItemType: '',
}
/*On hitting submit button, I'm logging the state and resetting the form fields after the state was stored in to newArray after appending*/
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state);
newArray = [...newArray, this.state];
console.log(newArray)
this.setState({
ItemName: '',
ItemPrice:'',
ItemDate: '',
ItemPlace: '',
ItemType: '',
})
}
/*When the input fields change, I'm updating the state*/
change =e =>{
// this.props.onChange({[e.target.name]:e.target.value})
this.setState({
[e.target.name]:e.target.value
})
}
/* toggling the showExtraDetails value after button was hit */
addExtraFoodDetails=() =>{
// e.preventDefault()
showExtraDetails = !showExtraDetails
console.log(showExtraDetails)
// e.preventDefault()
}
render(){
return(
<div>
<h5>Add Item</h5>
<form onSubmit={e => this.handleSubmit(e)}>
<input type="text" name="ItemName" placeholder="Enter the Item name"
value={this.state.ItemName}
onChange={e=> this.change(e)}
/>
<input type="number" name="ItemPrice" placeholder="Enter the item price"
value={this.state.ItemPrice}
onChange={e=>this.change(e)}
/>
<input type="date" name="ItemDate"
value={this.state.ItemDate}
onChange={e=>this.change(e)}
/>
<br/>
<input type="submit" name="submitItem" value="Save" />
</form>
<button onClick={this.addExtraDetails}>Add extra details</button>
<br/>
{showExtraDetails ?
(<div>
<input type="text" name="ItemPlace" value={this.state.ItemPlace}/>
<select name="ItemType" value={this.state.ItemType}>
<option value="none" disabled>--Select--</option>
<option value="type1">Type1</option>
<option value="type2">Type2</option>
<option value="type3">Type3</option>
<option value="others">Others</option>
</select>
</div>) : null
}
<br/>
<ul>
{newArray.map(item => <li>{item.ItemName}</li>)}
</ul>
</div>
)
}
But, when I hit the Add extra details button, I can only see the value of showExtraDetails as true/false after toggling, but the div is not getting updated with Showing/Hiding of the extra fields.
Am I missing something here? What is the best way to handle this?
I've seen in angular ngIf would do this. But I don't see such equivalent in React. I got some suggestions to make use of CSS styles by toggling the id's of the div. But I'm trying to apply something which is React specific.
Thanks.

In all probability, react is not re rendering. I suggest putting showExtraDetails in the state, and updating this state variable to cause a re render and thus cause your component to toggle correctly.

Related

React radio button requires two clicks to render

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

Why is change function not firing on radio input in react

Okay, so in my code, I have these two radio inputs, one with a fixed value, one with an input-field to take the dynamic value.
Now what I wanted to do is, when the user enters value in the input field, the corresponding radio button will get selected automatically, and the values will get updated as well. and if the user selects the default value, the state will get updated with the default value.
My code looks like this..
<ul className='list-unstyled mb-0 d-flex flex-column flex-lg-row justify-content-around'>
<li className='mr-4'>
<input
defaultChecked
onChange={() => updateState('timeLimit',defaultTime)}
type="radio"
value={defaultTime}
name='time'
className='mr-2'
id="defaultTime"/>
<label htmlFor="defaultTime"> {defaultTime} Mins. (default)</label>
</li>
<li>
<input
onChange={(e) => updateState('timeLimit',e.target.value)}
type="radio"
name='time'
value={customTime}
ref={customTimeRef}
className='mr-2'
id="customTime"/>
<label htmlFor="customTime">
<input
onChange={(e) => updateCustomTime(e.target.value)}
style={{outline:'none', border:'none',width:'9rem'}}
placeholder='Enter Your Time'
min='0'
className='border-bottom border-info pl-2 pb-1'
type="number"/> Mins. (custom)
</label>
</li>
</ul>
The functions are defined as
const updateCustomTime = (val) => {
if(customTimeRef.current.checked){
setCustomTime(val)
updateState('timeLiimit',val)
}
else{
customTimeRef.current.checked=true
setCustomTime(val)
updateState('timeLiimit',val)
}
}
Now the issue is, when I type into my input field, the updateState function is fired, the radio gets checked, but if I click on the radio buttons afterwards, they aren't firing the onchange events associated.
What's wrong here ? And how to achieve the desired result ??
Check this component
use a boolean state to set the checked property
const App = () => {
const [useDefault, setUseDefault] = React.useState(true)
return (
<div>
<div>
<input type="radio" name="time" checked={useDefault} onClick={() => setUseDefault(true)} />
</div>
<div>
<input type="radio" name="time" checked={!useDefault} />
<input type="text" onKeyUp={() => setUseDefault(false)} />
</div>
</div>
)
}
ReactDOM.render(
<App />,
document.getElementById('root')
);

How to set the default value of a dropdown list to a state variable in Reactjs

I have a React component which contains a textbox, dropdown list, and a submit button.
I capture values of the textbox and a dropdown list using an 'OnChange' event as follows.
<div className="form-group">
<label htmlFor="accountName">Account Name</label>
<input type="text" id="accountName" className="form-control" name="accountName" value={this.state.accountName} onChange={(e)=>this.change(e)}></input>
</div>
<div className="form-group">
<label htmlFor="originatedBy">Originated By</label>
<select className="form-control" id="originatedBy" name="originatedBy" value={this.state.originatedBy} onChange={(e)=>this.change(e)}>
<option>value1</option>
<option>value2</option>
<option>value3</option>
</select>
</div>
<div className="form-group row ml-md-1">
<button type="submit" className="btn btn-outline-primary btn-block" onClick={(e)=>this.addRecord(e)}>Add Record</button>
</div>
And in the Js section, I have,
class AddRecordView extends Component{
state={
accountName:"",
originatedBy:""
}
change(e){
this.setState({[e.target.name]:e.target.value});
}
addRecord(e){
e.preventDefault(e);
const user={
accountName : this.state.accountName,
originatedBy : this.state.originatedBy,
}
console.log(user);
var url = <url_of_the_endpoint>";
axios.post(url, {
user
},{
headers: {
'Accept': 'application/json'
}
})
.then(function(response){
console.log(response);
})
.catch(function(error){
console.log(error);
});
}
render(){
return(
<html_section>
);
}
}
export default AddRecordView;
The 'accountName' and the 'originatedBy' values are simply set when there is a change in the textbox and dropdown-list respectively.
However, if I let the default value (the value which shows when the form is loaded) of the dropdown-list remains unchanged and Submit the data, it doesn't trigger the 'OnChange' event and passes,
{accountName: 'some_value', originatedBy: ""} to the backend.
How can I make the 'originatedBy' attribute to take the default value of the dropdown-list. Please share your ideas on how to make it work (maybe from the constructor or any other suitable method).
Any suggestions will be helpful.

react - how to show relevant element when click button

I have component that renders jsx like this
<section>
<div>
<input type="text" class="hide" />
<button id={item.uniqueID}>show input</button>
</div>
<div>
<input type="text" class="hide" />
<button id={item.uniqueID}>show input</button>
</div>
<div>
<input type="text" class="hide" />
<button id={item.uniqueID}>show input</button>
</div>
</section>
I want this behavior, when I click the button in the first div, the input in the first div will show. Similarly, I click the button in the third div the input in third div will show.
How you do that in react?
If it were me I would make a new component out of:
show input
Lets call it <InputToggler/>
and then it would have a state of inputHidden for its own input and use classes to determine if it should show or not and the button would have an onclick handler to toggle the state of hidden or shown. Here is a pen showing exactly that
http://codepen.io/finalfreq/pen/VKPXoN
class InputToggler extends React.Component {
constructor() {
super();
this.state = {
inputHidden: true
}
}
toggleInput = () => {
this.setState({
inputHidden: !this.state.inputHidden
})
};
render() {
const inputClass = this.state.inputHidden ? 'hide' : '';
const buttonLabel = this.state.inputHidden ? 'show input' : 'hide input'
return (
<span>
<input type="text" className={inputClass} />
<button onClick={this.toggleInput} id={this.props.item.uniqueID}>
{buttonLabel}
</button>
</span>
)
}
}
This is the concept not the exact code.
Each button should have onClick with callback to a function ex. toggleShow
<button id={item.uniqueID} onClick={this.toggleShow.bind(this)}>show input</button>
toggleShow do something like:
toggleShow(e){
var item = e.target.id;
this.setState({inputClassName1: "hide"})
at the same time the input field classname should refer to the state
Note that I omitted the fact that you have multiple objects, you may want to handle their references in arrays.

React accessing children in form

I can not really access my dynamically generated children in a component. I found some cases on the internet, it seems like a common problem but nothing i could properly relate to or it was not really well documented so i got more confused.
I have a form which has a button and every time a press the button, subform is added to the form.
render: function() {
var prop_forms = [];
for(var i = 1; i <= this.state.count; i++){
prop_forms.push(<App.Form.Property reference={i}/>);
}
return(
<div>
<h2>New model</h2>
<form className="form" callback={this.submited}>
<label>Name:</label>
<input type="text" ref="name" className="fancy_input" required/>
<label><input type="checkbox" ref="include_endpoints"/> Include basic endpoints</label>
<h3>Properties <a onClick={this.add_property}><span className="glyphicon glyphicon-plus"></span></a></h3>
{prop_forms}
<button className="btn" onClick={this.submited} type="button">Add model to the canvas</button>
</form>
</div>
);
}
every time a click a button, this.state.count is incremented so I get one more App.Form.Property component. I am passing the i variable so i can use it in my ref parameter in the App.Form.Property component.
render: function(){
var input_ref = "property_"+this.props.reference+"_input";
var select_ref = "property_"+this.props.reference+"_select";
return(
<div className="property_form">
<input className="fancy_input" ref={input_ref} type="text" placeholder="Property name..."/>
<select className="fancy_select" ref={select_ref}>
<option value="string">String</option>
<option value="integer">Integer</option>
<option value="double">Double</option>
</select>
</div>
);
}
My problem is that when i submit the form, I can not access the children via ref. I can only address name and include_endpoints but nothing from the App.Form.Property component.
Add a function getSubmitData in your form component that encapsulates the children from the outer element

Categories