I'm trying to render components based on the checkbox selection. My approach was as follows:
class ReportMainCat extends Component {
constructor(props) {
super(props);
this.report_next = this.report_next.bind(this);
};
report_next() {
if(this.refs.sexual.checked) {
return <PostOptionBar/>
}
}
render() {
return (
<div className="text_align_left">
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="sexual"/>
<a>Sexual Content</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="selfharm"/>
<a>Threat or self harm</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="abuse"/>
<a>Abuse or bullying</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="illegal"/>
<a>Illegal substances</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="discrimination"/>
<a>Discrimination</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="copyright"/>
<a>Copyright or spam</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="nopermission"/>
<a>Humiliating, embarassing or posted without permission</a>
</div>
<button className="float_right" onClick={this.report_next}>Next</button>
{this.report_next()}
</div>
)
}
}
I'm checking if the checkbox is checked and rendering the component accordingly, but I keep getting this error:
Uncaught TypeError: Cannot read property 'checked' of undefined
How do I fix this? Or is this the best approach to do what I want to do?
It's advised not to use string refs in react components.
https://facebook.github.io/react/docs/refs-and-the-dom.html
So refs must be used in this manner
ref={(input) => { this.textInput = input; }}
So your input tag should be something like this
<input type="checkbox" ref={(input) => { this.sexualInput = input; }} />
And then in report_next() function you can get that value by using.
this.sexualInput.checked
Also do try to avoid using so many refs. Use state as much as possible in react components.
Suggestion As per DOC:
If you worked with React before, you might be familiar with an older
API where the ref attribute is a string, like "textInput", and the DOM
node is accessed as this.refs.textInput. We advise against it because
string refs have some issues, are considered legacy, and are likely to
be removed in one of the future releases. If you're currently using
this.refs.textInput to access refs, we recommend the callback pattern
instead.
Changes:
1. Returning a component on click of button will not do anything, for that you need to define a separate function just for onClick.
2. You need to use some state variable otherwise component will not re-rendered automatically and onclick of button you need to update that state value.
Check this snippet:
class ReportMainCat extends React.Component {
constructor(props) {
super(props);
this.state = {
renderComponent: false
}
this.buttonClick = this.buttonClick.bind(this);
};
report_next(){
if(this.refs.sexual && this.refs.sexual.checked){
return <div> hello </div>
}
}
buttonClick(){
this.setState({
renderComponent: true
})
}
render() {
return (
<div className="text_align_left">
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="sexual"/>
<a>Sexual Content</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="selfharm"/>
<a>Threat or self harm</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="abuse"/>
<a>Abuse or bullying</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="illegal"/>
<a>Illegal substances</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="discrimination"/>
<a>Discrimination</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="copyright"/>
<a>Copyright or spam</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="nopermission"/>
<a>Humiliating,embarassing or posted without permission</a>
</div>
<button className="float_right" onClick={this.buttonClick}>Next</button>
{this.report_next()}
</div>
)
}
}
ReactDOM.render(<ReportMainCat/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'/>
Use the SyntheticEvent, 'e'. Below is an example:
const element1 = "male";
const element2 = "female";
<input
type="checkbox"
name={element1}
value={element1}
onChange={this.handleChange}
/>
<label for="element" style={{ fontSize: 35 }}>
{element2}
</label>
<input
type="checkbox"
name={element2}
value={element2}
onChange={this.handleChange}
/>
<label for="element" style={{ fontSize: 35 }}>
{element2}
</label>
handleChange = (e) => {
// to find out if it's checked or not; returns true or false
const checked = e.target.checked;
// to get the checked value
const checkedValue = e.target.value;
// to get the checked name
const checkedName = e.target.name;
//then you can do with the value all you want to do with it.
};
class ReportMainCat extends React.Component {
constructor(props) {
super(props);
this.state = {
renderComponent: false
}
this.buttonClick = this.buttonClick.bind(this);
};
report_next(){
if(this.refs.sexual && this.refs.sexual.checked){
return <div> hello </div>
}
}
buttonClick(){
this.setState({
renderComponent: true
})
}
render() {
return (
<div className="text_align_left">
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="sexual"/>
<a>Sexual Content</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="selfharm"/>
<a>Threat or self harm</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="abuse"/>
<a>Abuse or bullying</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="illegal"/>
<a>Illegal substances</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="discrimination"/>
<a>Discrimination</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="copyright"/>
<a>Copyright or spam</a>
</div>
<div className="width_100 margin_bottom10px">
<input type="checkbox" ref="nopermission"/>
<a>Humiliating,embarassing or posted without permission</a>
</div>
<button className="float_right" onClick={this.buttonClick}>Next</button>
{this.report_next()}
</div>
)
}
}
ReactDOM.render(<ReportMainCat/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min`enter code here`.js"></script>
<div id='app'/>
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>
My code is not changing the text color of the label element to #ffffff. No errors are logged.
JS Code
$(document).ready(() => {
$('.label').on("click", () => {
$(this).css("color", "#ffffff")
})
})
HTML Code
<div id="q1">
<img src="lizerds/l2.jpeg" class="img"/>
<div>
<div class="radioWrapper">
<label class="label">
<input type="radio" id="q1Snake" class="radio" name="q1radio">
Snake
</label>
</div>
<div class="radioWrapper">
<label class="label">
<input type="radio" id="q1Lizard" class="radio" name="q1radio">
Legless Lizard
</label>
</div>
</div>
</div>
You are almost there. Use currentTarget to catch current element.
Note: Please avoid inline CSS, instead of inline use class.
$(document).ready((elm) => {
$('.label').on("click", (elm) => {
var $this = $(elm.currentTarget);
$('.label').removeClass('yourClss'); // Remove previous added class before add class in current markup
$this.addClass('yourClss')
})
})
.yourClss {
color: #ffffff
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="q1">
<img src="lizerds/l2.jpeg" class="img" />
<div>
<div class="radioWrapper">
<label class="label">
<input type="radio" id="q1Snake" class="radio" name="q1radio">
Snake
</label>
</div>
<div class="radioWrapper">
<label class="label">
<input type="radio" id="q1Lizard" class="radio" name="q1radio">
Legless Lizard
</label>
</div>
</div>
</div>
You can not use this in an anonymous function to refer to the local instance. Change the arrow function to a "function" and your code will work as expected:
$(document).ready(() => {
$('.label').on("click", function() {
$(this).css("color", "red")
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="q1">
<img src="lizerds/l2.jpeg" class="img"/>
<div>
<div class="radioWrapper">
<label class="label">
<input type="radio" id="q1Snake" class="radio" name="q1radio">
Snake
</label>
</div>
<div class="radioWrapper">
<label class="label">
<input type="radio" id="q1Lizard" class="radio" name="q1radio">
Legless Lizard
</label>
</div>
</div>
</div>
This problem is happening because you're trying to achieve this context with an arrow function.
As the official MDN documentation says:
Arrow function: "Does not have its own bindings to this or super, and should not be used as methods."
You should be doing this:
$(document).ready(() => {
$('.label').on("click", function() {
$(this).css("color", "#ffffff")
})
})
Instead of this
$(document).ready(() => {
$('.label').on("click", () => {
$(this).css("color", "#ffffff")
})
})
You have to catch current element in your function. Please use this code
$(document).ready((elem) => {
$('.label').on("click", (elem) => {
var current = $(elem.currentTarget);
$(current).css("color","#ffffff");
})
})
I am trying to convert the following component to a functional one so I could use the react context API?
The JSX code for the component I want to convert
class pizzaModal extends Component {
state = {
selected: "small",
showModal: true,
selectedOrder: null
}
toggleHandler = (size)=> ()=>{
this.setState({
toggle: size
});
}
addToOrders = (p)=>{
this.setState(prevState=>({
selectedOrder: p
}))
}
render (){
let attachedClasses = [styles.ImageContainer]
if(this.state.toggle==='small'){
attachedClasses = [styles.ImageContainer, styles.Small]
}
if(this.state.toggle==="medium"){
attachedClasses = [styles.ImageContainer, styles.Medium]
}
if(this.state.toggle==="large"){
attachedClasses=[styles.ImageContainer, styles.Large]
}
return (
<Aux>
<div className={styles.Pizzamodal}>
<div className={styles.ModalContainer}>
<div className={attachedClasses.join(' ')}>
<img src={this.props.image} alt="pizzapicture"/>
</div>
<div className={styles.DetailsContainer}>
<div>
<div className={styles.TextDetails}>
<h1>{this.props.name}</h1>
<p>{this.props.ingredients}</p>
</div>
<div>
<div className={styles.Form}>
<form className={styles.switchButton}>
<input type="radio" name="pizza" id="small" value="small" onChange={this.toggleHandler("small")}
checked={this.state.toggle==="small"}/>
<label for="small">Small</label>
<input type="radio" name="pizza" id="medium" value="medium" onChange={this.toggleHandler("medium")}
checked={this.state.toggle==="medium"}/>
<label for="medium">Medium</label>
<input type="radio" name="pizza" id="large" value="large" onChange={this.toggleHandler("large")}
checked={this.state.toggle==="large"}/>
<label for="large">Large</label>
</form>
</div>
<div className={styles.orderButton}>
<button onClick={this.props.addToOrders}>Add to basket for ₦{this.props.price}</button>
</div>
</div>
</div>
</div>
<div className={styles.Navbar} onClick={this.props.clicked}>
<div></div>
<div></div>
</div>
</div>
</div>
</Aux>
)
}
}
export default pizzaModal;
This is what I have done
const PizzaModal= (props) => {
const [Selected, setSelected] = useState('small')
const toggleHandler = (size)=>{
setSelected({
toggle: Selected
});
}
/*const [orders, setOrders] = useContext([CartContext]);
const addToOrders=()=>{
const pizza = {name: this.props.name, ingredients: this.props.ingredients, image: this.props.image, price: this.props.price}
setOrders([...orders, pizza])
}*/
let attachedClasses = [styles.ImageContainer]
if(setSelected(Selected==='small')){
attachedClasses = [styles.ImageContainer, styles.Small]
}
if(setSelected(Selected==="medium")){
attachedClasses = [styles.ImageContainer, styles.Medium]
}
if(setSelected(Selected==="large")){
attachedClasses=[styles.ImageContainer, styles.Large]
}
return (
<Aux>
<div className={styles.Pizzamodal}>
<div className={styles.ModalContainer}>
<div className={attachedClasses.join(' ')}>
<img src={props.image} alt="pizzapicture"/>
</div>
<div className={styles.DetailsContainer}>
<div>
<div className={styles.TextDetails}>
<h1>{props.name}</h1>
<p>{props.ingredients}</p>
</div>
<div>
<div className={styles.Form}>
<form className={styles.switchButton}>
<input type="radio" name="pizza" id="small" value="small" onChange={toggleHandler("small")}
checked={setSelected(Selected==='small')}/>
<label for="small">Small</label>
<input type="radio" name="pizza" id="medium" value="medium" onChange={toggleHandler("medium")}
checked={setSelected(Selected==='medium')}/>
<label for="medium">Medium</label>
<input type="radio" name="pizza" id="large" value="large" onChange={toggleHandler("large")}
checked={setSelected(Selected==='large')}/>
<label for="large">Large</label>
</form>
</div>
<div className={styles.orderButton}>
<button >Add to basket for ₦{props.price}</button>
</div>
</div>
</div>
</div>
<div className={styles.Navbar} onClick={props.clicked}>
<div></div>
<div></div>
</div>
</div>
</div>
</Aux>
)
}
export default PizzaModal;
I have no error messages on my IDE or on the webpage but when I click on the button that toggles the modal on I get a blank white screen with no error messages.
couple of mistakes i spotted in your code see if this changes anything
You dont need a seperate toggleHandler function to change value of Selected that is what setSelected is there for.
You gave setSelected an object
setSelected({toggle: Selected});
instead u should give it the value of Selected
setSelected(Selected);
And in all the if statements
if(setSelected(Selected==='small'))
is wrong u just have to check
if(Selected==='small')
4.And finally in OnChange
onChange={toggleHandler("small")}
you can just call setSelected
onChange={() => setSelected("small")}
The useState hook returns the current value of the state variable and a function to change it. In your case with
const [selected, setSelected] = useState('small')
you would use selected anywhere you previously would have used this.state.selected and use setSelected() anywhere you previously would have used this.setState({ selected }). So the first issue in your code is the misuse of the setter function when reading the state value.
When you want to pass a function to a component, you have to make sure you're passing the function and not a call to the function. For example
onChange={toggleHandler("large")}
will immediately get the return value of toggleHandler("large") and try to call that when the value changes. Your definition of toggleHandler doesn't return anything, so when you change your radio buttons, you're actually just trying to call undefined as a function, which of course doesn't work.
Also, the onChange handler of an input passes a synthetic event. You should use that to extract which radio button was pressed.
Try something like this:
const PizzaModal = (props) => {
const [selected, setSelected] = useState('small')
const toggleHandler = (event) => {
setSelected(event.target.value);
}
let attachedClasses = [styles.ImageContainer]
if (selected === 'small')) {
attachedClasses = [styles.ImageContainer, styles.Small]
}
if (selected === "medium")) {
attachedClasses = [styles.ImageContainer, styles.Medium]
}
if (selected === "large")) {
attachedClasses=[styles.ImageContainer, styles.Large]
}
return (
<Aux>
<div className={styles.Pizzamodal}>
<div className={styles.ModalContainer}>
<div className={attachedClasses.join(' ')}>
<img src={props.image} alt="pizzapicture"/>
</div>
<div className={styles.DetailsContainer}>
<div>
<div className={styles.TextDetails}>
<h1>{props.name}</h1>
<p>{props.ingredients}</p>
</div>
<div>
<div className={styles.Form}>
<form className={styles.switchButton}>
<input type="radio" name="pizza" id="small" value="small" onChange={toggleHandler} checked={selected === 'small'}/>
<label for="small">Small</label>
<input type="radio" name="pizza" id="medium" value="medium" onChange={toggleHandler} checked={selected === 'medium'}/>
<label for="medium">Medium</label>
<input type="radio" name="pizza" id="large" value="large" onChange={toggleHandler} checked={selected === 'large'}/>
<label for="large">Large</label>
</form>
</div>
<div className={styles.orderButton}>
<button >Add to basket for ₦{props.price}</button>
</div>
</div>
</div>
</div>
<div className={styles.Navbar} onClick={props.clicked}>
<div></div>
<div></div>
</div>
</div>
</div>
</Aux>
)
}
export default PizzaModal;
For future reference, errors also come through in the browser's Javascript console (usually in the developer tools section). You can check there for errors. My guess is that some combination of trying to call undefined as a function and a render loop due to the setSelected calls is what was causing your issue.
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))}
In last question I had assistance to create a code to save the state of a fairly complex toggle state. When a radio button is selected a checkbox slides down, when that checkbox is selected another one slides down. The reverse also occurs. Much of the code I do not understand. The problem now is that it works perfectly in jsfiddle.
https://jsfiddle.net/tomik23/ovysmutL/7/
However, it does not function on my webpage. When localstorage restores the state back to the webpage after a page refresh it automatically 'unchecks' the checkboxes about 2 seconds after load when they should have remained checked.
I totally stripped down my page to try to isolate this issue...the problem still exists. I read and tried all the similar stackoverflow problems eg( modified forms, added doc ready function,etc)... but obviously none of them helped.
The code works prior to localstorage insertion. When page is refreshed localstorage restores the state back to the webpage but it automatically 'unchecks' the checkboxes about 2 seconds after load when they should have remained checked. Does ANYBODY know what is going on AND HOW TO FIX THIS? I truly appreciate the help.
**HTML**
<form class="form" id="form-a" method="post" autocomplete="on">
<fieldset>
<div>
<p>
<label class="yes_text">Yes</label>
<span>
<input type="radio" data-show="next-a" id="dog" name="answer_name" value="yes">
</span>
</p>
<p>
<label>No</label>
<span>
<input type="radio" name="answer_name" value="no" checked>
</span>
</p>
</div>
</fieldset>
<fieldset id="next-a" class="hidden">
<div class="red">
<div>
<p>Include Red Dogs:</p>
</div>
<div>
<p>
<label class="yes_text_include">select to include</label>
<span>
<input type="checkbox" data-show="next-b" id="cat" class="red" name="red_name" value="">
</span>
</p>
</div>
</div>
<div id="next-b" class="hidden">
<div>
<p>Include Green Dogs:</p>
</div>
<div>
<p>
<label>select to include</label>
<span>
<input type="checkbox" name="green_name" class="cat" value="">
</span>
</p>
</div>
<div>
<p>
<label>select to include</label>
<span>
<input type="checkbox" name="blue_name" class="cat" value="">
</span>
</p>
</div>
</div>
</fieldset>
</form>
<form class="form" id="form-b" method="post" autocomplete="on">
<fieldset>
<div>
<p>
<label class="yes_text">Yes</label>
<span>
<input type="radio" data-show="next-a" id="dog" name="answer_name" value="yes">
</span>
</p>
<p>
<label>No</label>
<span>
<input type="radio" name="answer_name" value="no" checked>
</span>
</p>
</div>
</fieldset>
<fieldset id="next-a" class="hidden">
<div class="red">
<div>
<p>Include Red Dogs:</p>
</div>
<div>
<p>
<label class="yes_text_include">select to include</label>
<span>
<input type="checkbox" data-show="next-b" id="cat" class="red" name="red_name" value="">
</span>
</p>
</div>
</div>
<div id="next-b" class="hidden">
<div>
<p>Include Green Dogs:</p>
</div>
<div>
<p>
<label>select to include</label>
<span>
<input type="checkbox" name="green_name" class="cat" value="">
</span>
</p>
</div>
</div>
</fieldset>
</form>
**Javascript**
class CheckForm {
constructor(option) {
const forms = document.querySelectorAll(`${option}`);
forms.forEach(form => {
const formname = form.id;
this.formCheck(formname);
this.checkChecked(formname);
});
}
formCheck(formName) {
const form = document.querySelector(`#${formName}`);
form.addEventListener('click', e => {
const { target: { type, value, id, dataset: { show } } } = e;
switch (type) {
case 'radio': {
if (value === 'yes') {
$(`#${formName}`).find(`#${show}`).show(200);
this.saveToLocalstore(formName);
} else {
$(`#${formName} fieldset`).next().hide(200);
document.querySelector(`#${formName}`).reset();
localStorage.removeItem(formName);
this.removeAllChecked(formName);
}
break;
}
case 'checkbox': {
$(`#${formName}`).find(`#${show}`).toggle(200);
this.saveToLocalstore(formName);
if (id) {
this.removeAllChecked(formName, id);
}
break;
}
default:
break;
}
});
}
saveToLocalstore(formName) {
let allInput = document.querySelectorAll(`#${formName} input`);
let object = {};
allInput.forEach(item => {
object[item.name] = item.type === 'radio' ? true : item.checked;
});
localStorage.setItem(formName, JSON.stringify(object));
}
checkChecked(formName) {
const data = JSON.parse(localStorage.getItem(formName));
if (data) {
let i = 1;
for (let [key, value] of Object.entries(data)) {
const item = document.querySelector(`#${formName} input[name='${key}']`);
setTimeout(() => {
if (value) {
item.click();
}
}, i * 1000);
i++;
}
}
}
removeAllChecked(formName, id) {
if (id) {
let allInput = document.querySelectorAll(`#${formName} .${id}`);
allInput.forEach(item => {
item.checked = false;
});
} else {
const allHidden = document.querySelectorAll(`#${formName} .hidden`);
allHidden.forEach(item => {
item.removeAttribute('style', '');
});
}
}
}
new CheckForm('.form');
**CSS**
.hidden {
display: none;
}