React.js - How to check the radio correctlly - reactjs

There is a litter bug like this:
There are three radioGroup , we call it A , B, C.
A:Has 2 radios ,it will control to render B or render C.
B:Has 4 radios,default B-1(the first radio of B)
C:Has 10 radios,default C-1(this first radio of C)
when I choose A-1,the B is rendered,the default is B-1.
Then I choose B-2,then I choose A-2.
The Error come out,I found the C-2 is Checked!
But I didn`t click the C-2 at all.
So Why this happened? How could I fixed it?
class Tanx extends React.Component{
constructor() {
super();
this.subMit = this.subMit.bind(this);
this.setData = this.setData.bind(this);
this.setGreatspec = this.setGreatspec.bind(this);
this.setPlatform = this.setPlatform.bind(this);
this.state = {
platform:"PC",
create_spec:"99",
ad:null
};
}
setGreatspec(val) {
this.setState({
create_spec:val
})
}
setPlatform(val) {
console.log(this);
this.setState({
platform:val
});
}
setData(val){
this.setState({
ad:val
})
}
subMit() {
let create_spec = this.state.create_spec;
let platform = this.state.platform;
let self = this;
console.log(this.state);
// $.ajax({
// url:"/req/gdt/"+platform+"/"+create_spec,
// type:'get',
// success:function(res){
// // var ad = res.msg&&res.msg.seatbid[0].bid[0];
// var ad = res.msg
// self.setData(ad);
// console.log(res);
// },
// error:function(err){
// console.log(err);
// }
// })
}
render() {
var ad = this.state.ad;
if(ad){
var ad_html = (<div className="col-lg-4">
<pre style={{background:"#eee",padding:"10px",maxHeight:"500px",overflow:"scroll"}}>
<code style={{color:"green",fontSize:"14px"}}>
{JSON.stringify(ad,null,"\t")}
</code>
</pre>
</div>);
}else{
var ad_html = "";
}
var platform = this.state.platform;
if(platform==='PC'){
var radio_box = <RadioBox titles={['99','23','12','2']} name="create_spec_moblie" getVal={this.setGreatspec} />
}else{
var radio_box = <RadioBox titles={['80','207','208','212','147','148','149','150','79','58','59','70','113','114','10','28','31','35','69','65','133','134']} name="create_spec_moblie" getVal={this.setGreatspec} />
}
return(
<div className="row">
<div className="col-lg-3">
<FormGroup name="Platform">
<RadioBox titles={['PC','Mobile']} name="platform" getVal={this.setPlatform} />
</FormGroup>
<FormGroup name="Create_spec">
{radio_box}
</FormGroup>
<button className="btn btn-info btn-lg" onClick={this.subMit}>Submit</button>
</div>
{ad_html}
</div>
)
}
}

You need to understand the React internals for this. React needs a way to identify the "uniqueness" of a component. In your example you're using RadioBox with the same name and injecting in the parent component output. In the end, what react sees is quite the same markup but with only the titles property beeing changed, so internally, React will only change the props passed to the component (using the same component whatsoever).
So, in the end your component outputs one of the following markups:
<div className="row">
<div className="col-lg-3">
<FormGroup name="Platform">
<RadioBox titles={['PC','Mobile']} name="platform" getVal={this.setPlatform} />
</FormGroup>
<FormGroup name="Create_spec">
<RadioBox titles={['99','23','12','2']} name="create_spec_moblie" getVal={this.setGreatspec} />
</FormGroup>
<button className="btn btn-info btn-lg" onClick={this.subMit}>Submit</button>
</div>
<AdHTML here... />
</div>
or
<div className="row">
<div className="col-lg-3">
<FormGroup name="Platform">
<RadioBox titles={['PC','Mobile']} name="platform" getVal={this.setPlatform} />
</FormGroup>
<FormGroup name="Create_spec">
<RadioBox titles={['80','207','208','212','147','148','149','150','79','58','59','70','113','114','10','28','31','35','69','65','133','134']} name="create_spec_moblie" getVal={this.setGreatspec} />
</FormGroup>
<button className="btn btn-info btn-lg" onClick={this.subMit}>Submit</button>
</div>
<AdHTML here... />
</div>
As you can see, either version you choose, the difference is the titles attribute passed to the second RadioBox component. i.e. titles={[a, different, set, of, titles]}
So what the library determines in this case is that you're using the same RadioBox component with a slight change - i.e. title - and uses the same cached component and re-renders it with the different parameter. The internal state of the component, thus, remains unchanged.
But you actually need the same component being rendered uniquely for each of your cases. So you have to pass an id parameter in each case, and (maybe) remove the name attribute since it's completely useless.
So in each of your case you have to pass an id parameter that should be unique.
<RadioBox title={[B, checkbox, titles]} id="b-checkbox" />
and
<RadioBox title={[C, checkbox, titles]} id="c-checkbox" />

Related

React can not use conditionally rendering on a component due to variables being nested inside of my form

I want to conditionally render a component in this case if the user submits a wrong answer, the input is stored as a javascript object called data and gets converted to a string called userInput.
After looking around, I got recommended to create a conditional rendering with a state outside of the form, but the problem I ran across is that since the variables are initialized inside of my form, i can't use ternaries to conditionally render my component in so I'm a bit stuck in what to do.
<main class="gameSection">
<h1>Welcome to League of Wordle!</h1>
<form
onSubmit={handleSubmit((data) => {
let userInput = data.guess;
console.log(userInput);
const championList = Object.keys(champions);
if (userInput.valueOf().toUpperCase() !== correctChampion.valueOf().toUpperCase()) {
<Wrong text="Class" alt="wrong img" img={wrong} />
}
})
}
>
<input
{...register("guess")} class="guess_input" placeholder="Enter Champion Name Here" type="text" />
<input class="guess_input" type="submit" />
</form>
</main>
I suggest you create a state to track if any answers submitted is wrong.
const [isWrong, setIsWrong] = useState(false)
Now, after each submit, update isWrong's value based on input.
onSubmit={handleSubmit((data) => {
let userInput = data.guess;
console.log(userInput);
const championList = Object.keys(champions);
if (userInput.valueOf().toUpperCase() !== correctChampion.valueOf().toUpperCase()) {
setIsWrong(true)
}
else {setIsWrong(false) } // logic in case of correct answer
})
}
Finally, you can implement conditional rendering:
<main class="gameSection">
<h1>Welcome to League of Wordle!</h1>
<form
...
>
<input
{...register("guess")} class="guess_input" placeholder="Enter Champion Name Here" type="text" />
<input class="guess_input" type="submit" />
{isWrong && <Wrong text="Class" alt="wrong img" img={wrong} /> }
</form>
</main>

How to get state of Reactstrap's CustomInput Switch component, and how to map switches from an array?

<FormGroup>
<div>
{this.props.diseases.map((disease, index) => (
<FormGroup>
<CustomInput
type="switch"
id="exampleCustomSwitch"
key={disease}
disease={disease}
onClick={(disease) => this.props.toggle(disease)}
label={disease}
/>
</FormGroup>
))
}
</div>
</FormGroup>
I want to be able to find out the state of the switch, whether it's switched on or off. Not sure how I'm able to do that? Am I to pass in a default value of some sort with 0 as off and 1 as on?
Presently, the switches are mapping appropriately from the array, but switching on or off only works for the first switch. So, if I click on any of the other switches, for some reason the first switch toggles.
For point #1,yYou can use e.target.checked to check the true/false status for a particular CustomInput; Check this stackblitz to see it work
For point #2 If you share your existing code, it will be easier to help with your specific scenario
relevant js:
class App extends Component {
constructor() {
super();
this.state = {
name: "World to React",
log: []
};
this.customInputSwitched.bind(this);
}
customInputSwitched(buttonName, e) {
let newStr = `we received ${e.target.checked} for ${buttonName}...`;
console.log(newStr);
let newLog = [...this.state.log, newStr];
this.setState({ log: newLog });
}
render() {
var testName = "modal for testing - click here";
return (
<div>
<Hello name={this.state.name} />
<p>Start editing to see some magic happen :)</p>
<Form>
<FormGroup>
<Label for="exampleCheckbox">Switches</Label>
<div>
<CustomInput
type="switch"
id="exampleCustomSwitch"
name="customSwitch"
label="Turn on this custom switch"
onChange={this.customInputSwitched.bind(this, "button1")}
/>
<CustomInput
type="switch"
id="exampleCustomSwitch2"
name="customSwitch"
label="Or this one"
onChange={this.customInputSwitched.bind(this, "button2")}
/>
<CustomInput
type="switch"
id="exampleCustomSwitch3"
label="But not this disabled one"
disabled
/>
<CustomInput
type="switch"
id="exampleCustomSwitch4"
label="Can't click this label to turn on!"
htmlFor="exampleCustomSwitch4_X"
disabled
/>
</div>
</FormGroup>
</Form>
{this.state.log}
</div>
);
}
}
UPDATE #1: In light of questioner's comment below
Few issues in your code at https://stackblitz.com/edit/react-rcqlwq
you have to instantiate Log in the state in the contstructor
the customInputSwitched function should pass the argument of the particular button, not a hard-coded 'button1' - so we add the index number of the disease
the ID of all the buttons can't be the same 'exampleCustomSwitch', so we just add the index number to ID
best practice in mapping as array is to include an index also, which has benefits (as shown in the next 2 points)
relevant working JS for your code/stackblitz:
class App extends Component {
constructor() {
super();
this.state = {
diseases: [
"Normal",
"Over inflated lungs",
"Pneumonia",
"Pneumothorax",
"Congestive cardiac failure",
"Consolidation",
"Hilar enlargement",
"Medical device",
"Effusion"
],
log: []
};
this.customInputSwitched.bind(this);
}
customInputSwitched(buttonName, e) {
let newStr = `we received ${e.target.checked} for ${buttonName}...`;
console.log(newStr);
let newLog = [...this.state.log, newStr];
this.setState({ log: newLog });
}
render() {
return (
<div>
<p>Start editing to see some magic happen :)</p>
<Form>
<FormGroup>
<Label for="exampleCheckbox">Switches</Label>
{this.state.diseases.map((disease, index) => {
//console.log(disease, index);
let idName = "exampleCustomSwitch"+index;
return (
<div key={index}>
<CustomInput
type="switch"
id={idName}
name="customSwitch"
label={disease}
onChange={this.customInputSwitched.bind(this, "button"+index)}
/>
</div>
);
}
)}
</FormGroup>
</Form>
{this.state.log}
</div>
);
}
}

How to change the state in conditional - React

I need to change the state of sibling components in my React App.
I use state and setstate
I need to change the state of sibling components. When loading the page, there must exist (visible in the page) <BkUser /> and when clicking "button id =" ds-visual "it must be deleted (<BkUser /> mustn't exist) and there must exist <BkDescanso />.
When you click on <BkSleep /> (in the div parent) you should remove <BkDescanso /> and show <BkUser />
This is the web.
There should never be <BkUser/> and <BkSleep> at the same time. <Bkuser /> is the blue block and <BkDescanso /> is the red block
This is my code:
Edit: I edit my original code because I fix the problem. This is the final OK Code. In the end the most important thing was the state conditional
{
this.state.usuario ? (<BkUser handleClick = {this.handleClick} usuario={this.state.usuario}/>): (<BkDescanso handleClick = {this.handleClick} usuario={this.state.usuario}/>)}
import React, { Component } from 'react';
class Header extends Component {
constructor(props) {
super(props);
this.state = {
usuario: true,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
usuario: !state.usuario
}));
//alert("Works button");
}
render(){
return (
<header className="header">
<div className="configuracion">
{
this.state.usuario
? (
<BkUser handleClick = {this.handleClick} usuario={this.state.usuario}/>
)
: (
<BkDescanso handleClick = {this.handleClick} usuario={this.state.usuario}/>
)}
<div className="content-btn">
<button id="config" className='btn btn--rounded'><span className="ico-configuracion"></span></button>
<button id="salir" className='btn btn--rounded'><span className="ico-exit"></span></button>
</div>
</div>
</header>
);
}
}
class BkUser extends Component{
render(){
return ((
<div className='usuario'>
<img src="../img//usuario.svg" alt="Imagen usuario"/>
<div className="content-usuario">
<span id="nm-usuario" className="h4">Hermione Jane Granger</span>
<span id="tp-usuario" className="h5">Supervisor</span>
</div>
<div className="content-descansos">
<div className="botones">
<button id="ds-visual" className='btn btn--rounded' onClick={this.props.handleClick}><span className="ico-visual"></span></button>
<button id="ds-admin" className='btn btn--rounded'><span className="ico-tiempo-administrativo"></span></button>
<button id="ds-otros" className='btn btn--rounded'><span className="ico-descanso"></span></button>
</div>
<div className="ds-actual">
<span id="ds-tipo">Administrativo</span>
<span id="ds-tiempo">00:08:47</span>
</div>
</div>
</div>
));
}
}
class BkDescanso extends Component {
render(){
return ((
<div className='usuario descanso' onClick={this.props.handleClick}>
<h3>Finalizar descanso</h3>
</div>
));
}
}
export default Header;
Right now handleClick works but always exist BkUser and BkDescanso. I need only one to exist. If you click on id = "ds-visual" the bkUser block should disappear and BkDescanso appear. Then if you click on div className = 'user rest' in BkUser there should only be BkDescanso.
I think that it is not able to know when it is true and when it is false to show or hide
Thanks a lot for the help.
You're missing two things:
First you have to pass the handleClick function to the BkUser component, and then you have to call it via this.props.handleClick.
...
<BkUser handleClick={this.handleClick} usuario={this.state.usuario} />
....
<button
id="ds-visual"
className="btn btn--rounded"
onClick={this.props.handleClick}
>
ds-visual
<span className="ico-visual" />
</button>
CodeSandbox here.
Read more here.
You can change the state of the siblings by passing a function from the parent via props into them.
In the end your siblings are the children of their parent.
You can read this articles on how to change the state of child components.
React js change child component's state from parent component
https://medium.freecodecamp.org/react-changing-state-of-child-component-from-parent-8ab547436271
An other thing you could look into would be React Redux.

checkbox hiding and showing component - react

I am building a small feature that has a checkbox styled as slider that, when turned on and off, should display another component - BatchWidget. The way I have it currently set up, it works on initial page load, and then hides as intended. However, when I go to "toggle" it back on to show the component again, it does not work. Is there an easy solution to this?
const Slider = (props) => {
return (
<div className="slider-container">
<label className="switch">
<input type="checkbox" checked={props.checked} onClick= {props.showWidget} />
<span className="slider round" />
</label>
<p className="batch-slider-title"> Batch Widget </p>
</div>
);
};
const Settings = ({showSlider}) => {
return (
<div className="settings">
<i className="icon-gear" onClick={() => showSlider()} />
</div>
);
}
class WidgetContainer extends Component {
constructor() {
super();
this.state = {
checked: true,
isSliderDisplayed: false,
};
this.showWidget = this.showWidget.bind(this);
this.showSlider = this.showSlider.bind(this);
}
showWidget() {
this.setState({
checked: !this.state.checked,
});
}
showSlider() {
this.setState({
isSliderDisplayed: !this.state.isSliderDisplayed,
});
}
render() {
const displayBatchWidget = this.state.checked ? <BatchWidget /> : null;
const displaySlider = this.state.isSliderDisplayed ? <Slider checked={this.state.checked} showWidget={this.showWidget} /> : null;
return (
<div>
<Settings showSlider={this.showSlider} />
{displaySlider}
{displayBatchWidget}
</div>
);
}
}
When I try to debug, it shows:
Warning: Failed form propType: You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`. Check the render method of `Slider`.
I think it is self-explanatory.
I've changed the line with checkbox to:
<input type="checkbox" checked={props.checked} onChange= {props.showWidget} />
Now, the batchWidget should hide and show on each click.
Reactjs matrial ui table check box hide
first do
<Table selectable={false}>
<TableHeader displaySelectAll={false} adjustForCheckbox={false}>
this method hide table header check box
then do <TableBody displayRowCheckbox={false}>
it hide table body checkbox
it work perfect.
reactjs

React : Is this possible to replace a "placeholder template tag" send as children?

I have for example this code below :
<AjaxForm>
<input type="hidden" name="xxx" value="xxx" />
<div className="grid">
<div className="gdcol-xs-11">
[[SUBMIT_BUTTON]]
</div>
<div className="gdcol-xs-11">
[[CANCEL_BUTTON]]
</div>
</div>
</AjaxForm>
And I would like, for example, be able in the AjaxForm component to replace the tag placeholder 'SUBMIT_BUTTON' by this :
<a href="javascript:void(0);" onClick={this.handleSubmit}>VALIDATE</a>
Is there a way to do this by iterating on this.props.children in the AjaxForm component ?
Is this possible to find some text pattern by crawling all the children ?
Should I have to use refs or a key ?
Thank you in advance !
---- EDIT
To add some informations, this is the render of the AjaxForm Component
return (
<form action="" method="post" ref={this.ajaxRef} id={this.props.id} onSubmit={this.onSubmit}>
<input type="hidden" name="form_id" value={this.props.id} />
{this.props.children}
<input type="submit" value="" className="fake-submit" />
<div id={("ajax-") + this.props.id + ("-messages-container")} className="ajax-form-messages"></div>
</form>
)
I think I understand your issue now. You're generating a component inside AjaxForm and you want to be able to place that component dynamically. In that case you should create another component called AjaxFormContents (or whatever your specific form should be called) which receives your generated component via props and places it wherever you want.
// AjaxForm.js
...
render() {
return React.cloneElement(this.props.children, {
submitButton: this.generateSubmitButton() // or however you're doing it
})
}
...
Now whatever component you put as a child will have access to this component.
// AjaxFormContents.js
...
render() {
return ( // arrange your form contents however you like!
<div>
<input />
{ this.props.submitButton }
</div>
)
}
Then in your parent component:
// Parent.js
...
render() {
return (
<AjaxForm>
<AjaxFormContents />
</AjaxForm>
)
}
This should work, however another approach -- using a higher order component (HOC) would be a nice solution here as well, because your AjaxForm doesn't display anything, it just wraps your form contents.. instead AjaxForm can be an HOC which passes a generated submit button component to the wrapped component.
var ajaxForm = function (WrappedComponent) {
return React.createClass({
generateSubmitButton() {
return <a>your special submit button </a>
},
render() {
<WrappedComponent submitButton={ this.generateSubmitButton() } />
}
})
}
Then you can have the exact same AjaxFormContents component as above and when you export it:
// or module.exports, whichever one you're using.
export default ajaxForm(AjaxFormContents)

Resources