I am new to react. I am trying to create a component that hides a div when a checkbox is clicked. The problem I am having is, if I introduce more than one checkbox the divs visibility is toggled. Is there an alternative way to allow the selection of all checkboxes?
The functionality should be: click a checkbox or multiple > div remains hidden until all checkboxes are cleared or unchecked.
JSX:
import React, { useState } from 'react';
function reactComponent() {
const [isChecked, setIsChecked] = useState(false);
const toggle = () => setIsChecked(!isChecked);
return (
<div>
<div>
<input type="checkbox" id="option" name="option" onClick={toggle} />
<label for="scales">option</label>
</div>
<div>
<input type="checkbox" id="option" name="option" onClick={toggle} />
<label for="scales">option</label>
</div>
<div className={isChecked ? "hide" : "block "}>
<h3 className="red bold">Content</h3>
<p>lorem Ipsum</p>
</div>
</div>
)
}
export default reactComponent
To achieve what you've described you could use controlled inputs for checkboxes and have a separate piece of state for every checkbox. Here is Codesandbox demo of an example below (you can change some to every in shouldShow flag if you need to show the div if and only if all the checkboxes are checked).
function App() {
const [isChecked, setIsChecked] = useState({ option1: false, option2: false })
const toggle = ({ target: { name } }) =>
setIsChecked({ ...isChecked, [name]: !isChecked[name] })
// Are there any checked ones?
const shouldShow = Object.values(isChecked).some(val => val)
return (
<>
<div>
<input
type="checkbox"
id="option1"
name="option1"
checked={isChecked.option1}
value={isChecked.option1}
onClick={toggle}
/>
<label for="option1">option1</label>
</div>
<div>
<input
type="checkbox"
id="option2"
name="option2"
checked={isChecked.option2}
value={isChecked.option2}
onClick={toggle}
/>
<label for="option2">option2</label>
</div>
<div className={shouldShow ? "hide" : "block "}>
<h3 className="red bold">Content</h3>
<p>lorem Ipsum</p>
</div>
</>
)
}
If you render your checkboxes from an array, you can always check if the length of that array is the same as the length of the checked array kept in state.
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const myOptions = ["option1", "option2", "option3", "option4"];
const [myChecked, setMyChecked] = useState([]);
const toggle = e => {
e.persist();
if (e.target.checked) {
setMyChecked(oldArray => [...oldArray, e.target.name]);
} else {
setMyChecked(oldArray => oldArray.filter(item => item !== e.target.name));
}
};
const showDiv = () => {
return myChecked.length === myOptions.length;
};
return (
<div>
{myOptions.map(option => (
<div>
<label>
<input type="checkbox" name={option} onChange={toggle} />
{option}
</label>
</div>
))}
<div className={showDiv() ? "block" : "hide "}>
<h3>Content</h3>
<p>lorem Ipsum</p>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Codesandbox
Related
I have this toggle react component. I am trying to access handleChangeTogle when i click on the Toggle but call is not reaching handleChangeTogle.
What am i doing wrong here?
const handleChangeTogle = () => {
setdomestic_voilence(!domestic_voilence);
};
<Toggle
checked={domestic_voilence}
text="Is Active"
onChange={() => handleChangeTogle}
offstyle="btn-danger"
onstyle="btn-success"
/>
import React from "react";
function Toggle(props) {
console.log(props);
const {
text,
size = "default",
defaultChecked,
disabled,
onChange,
offstyle = "btn-danger",
onstyle = "btn-success",
} = props;
let displayStyle = defaultChecked ? onstyle : offstyle;
return (
<>
<label>
<span className={` switch-wrapper`}>
<input
type="checkbox"
// checked={defaultChecked}
// onChange={(e) => onChange(e)}
/>
<span className={`${displayStyle} switch`}>
<span className="switch-handle" />
</span>
</span>
{/* <span className="switch-label">gyyghiyg</span> */}
</label>
</>
);
}
export default Toggle;
I tested your problem and solved it this way. (I used typescript with React. You can remove Interface and types).
Toggle.tsx
import React from "react";
import { ToggleInterface } from './interfaces';
const Toggle = ({ text, handleChange, offstyle, onstyle }: ToggleInterface) => {
return (
<>
<label>
<span className={`switch-wrapper`}>
<input
type="checkbox"
onChange={(e) => handleChange(e)} />
<span className="switch">
<span className="switch-handle" />
</span>
</span>
</label>
</>
);
}
export default Toggle;
App.tsx
const handleChangeToggle = () => {
console.log("handleChangeToggle is worked !!");
};
return (
<div className="App">
<Toggle
text="Is Active"
handleChange={() => handleChangeToggle() }
offstyle= "btn-danger"
onstyle= "btn-success"
/>
);
}
export default App;
interface.ts
export interface ToggleInterface {
text: string,
handleChange: Function,
offstyle: string,
onstyle: string
}
I have following code of Calculator.jsx where everything looks fine.The main thing I want to achieve is keyboard to displayed only on input click which is done but the keyboard does not seem to type though the following code looks fine. Are there any other way to show/hide keyboard only on input click as well as make keyboard be able to type. My code for Calculator.jsx is
Calculator.jsx
import React, { useState, useRef, useEffect } from 'react';
import './Calculator.css'
import { Link } from 'react-router-dom';
import Keyboard from "react-simple-keyboard";
import "react-simple-keyboard/build/css/index.css";
const Calculator = () => {
const [inputs, setInputs] = useState({});
const [layoutName, setLayoutName] = useState("default");
const [inputName, setInputName] = useState("default");
const keyboard = useRef();
const [keyboardVisibility, setKeyboardVisibility] = useState(false);
useEffect(() => {
function clickHanlder(e) {
if (
!(e.target.nodeName === "INPUT") &&
!e.target.classList.contains("hg-button") &&
!e.target.classList.contains("hg-row")
) {
setKeyboardVisibility(false);
}
}
window.addEventListener("click", clickHanlder);
return window.removeEventListener("click", clickHanlder, true);
}, []);
const onChangeAll = inputs => {
setInputs({ ...inputs });
console.log("Inputs changed", inputs);
};
const handleShift = () => {
const newLayoutName = layoutName === "default" ? "shift" : "default";
setLayoutName(newLayoutName);
};
const onKeyPress = button => {
console.log("Button pressed", button);
if (button === "{shift}" || button === "{lock}") handleShift();
};
const onChangeInput = event => {
const inputVal = event.target.value;
setInputs({
...inputs,
[inputName]: inputVal
});
keyboard.current.setInput(inputVal);
};
const getInputValue = inputName => {
return inputs[inputName] || "";
};
return (
<div>
<div className="bg">
<div className="deposit">
<div className="header">
<h1>Deposit Calculator</h1>
<div className="form">
<form className="calculator">
<div className="form-group">
<label for="depositAmount">Deposit Amount:</label>
<span className="rupees">Rs</span>
<input className="IInput"
type="text"
name='depositAmount'
placeholder='0'
value={getInputValue("depositAmount")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("depositAmount")
}}
/>
</div>
<div className="form-group">
<label for="interestRate">Interest Rate:</label>
<input className= "IIinput"
type="text"
name='Interest'
placeholder='0'
value={getInputValue("interestRate")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("interestRate")
}}
/>
<span className= "percent">%</span>
</div>
<div class="form-group">
<label for="Tenure">Tenure:</label>
<input className="Input"
type='number'
min='1'
max='5'
name='tenure'
placeholder='1 year'
value={getInputValue("tenure")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("tenure")
}}
/>
</div>
{ keyboardVisibility && (
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layoutName}
onChange={onChangeAll}
onKeyPress={onKeyPress}
/>
)}
</form>
<button className="calculate">Calculate
</button>
</div>
<div className="given">
<p >
Total Deposit: Rs 0
</p>
<p>
Interest: Rs 0
</p>
<p>
Maturity Amount: Rs 0
</p>
</div>
</div>
</div>
</div>
<Link to="/">
<button className="Back">
<i class="fas fa-angle-double-left"></i>
</button>
</Link>
</div>
);
};
export default Calculator;
You are setting the inputs state by spreading input string from keyboard onChangeAll into an object setInputs({ ...inputs }). If I enter ab it will set as {0: "a", 1:"b"}.
Update the onChange prop in Keyboard to onChangeAll and pass inputName prop with your inputName state value. Read react-simple-keyboard DOCS.
onChangeAll
const onChangeAll = (inputs) => {
console.log("Inputs changed", inputs);
setInputs(inputs);
};
Keyboard
{keyboardVisibility && (
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layoutName}
onChangeAll={onChangeAll}
onKeyPress={onKeyPress}
inputName={inputName}
/>
)}
CodeSandbox link
How to add the checkbox or radio button inside the map method. I have created question and answer app. I need to add checkbox or radio button for the answers. Below in the card component is where the question and answer is getting printed out. How can i add the radio button in there so user can check the answer.
import React, { useState, useEffect } from "react";
import { Fragment } from "react";
import "./Survey.css";
import CreateSurvey from "../modals/CreateSurvey";
import Card from "../card/Card";
const Survey = () => {
const [modal, setModal] = useState(false);
const [surveyList, setSurveyList] = useState([]);
useEffect(() => {
let arr = localStorage.getItem("surveyList");
if (arr) {
let obj = JSON.parse(arr);
setSurveyList(obj);
}
}, []);
const deleteSurvey = (index) => {
let tempList = surveyList;
tempList.splice(index, 1);
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(tempList);
window.location.reload();
};
const toggle = () => {
setModal(!modal);
};
const updateListArray = (obj, index) => {
let tempList = surveyList;
tempList[index] = obj;
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(tempList);
window.location.reload();
};
const saveSurvey = (surveyObj) => {
let tempList = surveyList;
tempList.push(surveyObj);
localStorage.setItem("surveyList", JSON.stringify(tempList));
setSurveyList(surveyList);
setModal(false);
};
return (
<Fragment>
<div className="header text-center">
<h5>Survey</h5>
<button className="btn btn-primary" onClick={() => setModal(true)}>
Create Survey
</button>
</div>
<div className="survey-container">
{surveyList &&
surveyList.map((obj, index) => (
<Card
surveyObj={obj}
index={index}
deleteSurvey={deleteSurvey}
updateListArray={updateListArray}
/>
))}
</div>
<CreateSurvey toggle={toggle} modal={modal} save={saveSurvey} />
</Fragment>
);
};
export default Survey;
//Card.js
import React, { useState } from "react";
import "./Card.css";
const Card = ({ surveyObj, deleteSurvey, index }) => {
const [modal, setModal] = useState(false);
const toggle = () => {
setModal(!modal);
};
const deleteHandler = () => {
deleteSurvey(index);
};
return (
<div>
<div className="card-wrapper mr-5">
<div className="card-top"></div>
<div className="survey-holder">
<span className="card-header">{surveyObj.name}</span>
<p className="answer"> {surveyObj.answerOne}</p>
<div className="icons">
<i className="far fa-edit edit"></i>
<i className="fas fa-trash-alt delete" onClick={deleteHandler}></i>
</div>
</div>
</div>
</div>
);
};
export default Card;
//Createsurvey.js
import React, { useState } from "react";
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import { Fragment } from "react";
const CreateSurvey = ({ modal, toggle, save }) => {
const [question, setQuestion] = useState("");
const [answerOne, setAnswerOne] = useState("");
const [answerTwo, setAnswerTwo] = useState("");
const [answerThree, setAnswerThree] = useState("");
const [answerFour, setAnswerFour] = useState("");
const changeHandler = (e) => {
const { name, value } = e.target;
if (name === "question") {
setQuestion(value);
} else {
setAnswerOne(value);
}
};
const saveHandler = (e) => {
e.preventDefault();
let surveyObj = {};
surveyObj["name"] = question;
surveyObj["answerOne"] = answerOne;
surveyObj["answerTwo"] = answerTwo;
surveyObj["answerThree"] = answerThree;
surveyObj["answerFour"] = answerFour;
save(surveyObj);
};
return (
<Fragment>
<Modal isOpen={modal} toggle={toggle}>
<ModalHeader toggle={toggle}>Create a Survey Question</ModalHeader>
<ModalBody>
<form>
<div>
<div className="form-group">
<label>Survey Questions</label>
<input
type="text"
className="form-control"
value={question}
name="question"
onChange={changeHandler}
/>
</div>
</div>
<div className="mt-2">
<label>Survey Answers</label>
<div className="form-group">
<label>Answer 1</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerOne}
name="answerOne"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 2</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerTwo}
name="answerTwo"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 3</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerThree}
name="answerThree"
onChange={changeHandler}
/>
</div>
<div className="form-group">
<label>Answer 4</label>
<input
type="text"
className="form-control mt-2 mb-2"
value={answerFour}
name="answerFour"
onChange={changeHandler}
/>
</div>
</div>
</form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={saveHandler}>
Create
</Button>
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
</Fragment>
);
};
export default CreateSurvey;
What I am understanding is that you want to add multiple component in map method. You can simply do it as:
{surveyList &&
surveyList.map((obj, index) => (
<>
<Card
surveyObj={obj}
index={index}
deleteSurvey={deleteSurvey}
updateListArray={updateListArray}
/>
<input type="checkbox" name="userchoice" />
</>
))}
On click on a button how can we create a dynamic form url with below fields using react hooks and url globally valid only for 48 hrs.
https://localhost/aB123GHedFGH138HGxYz/recommendform
import React, { useState, useEffect, useRef } from "react";
import "./styles.css";
export default function App() {
// nominee text field
// description
// nominatedby
// save button
// cancel button
const [createForm, setCreateForm] = useState([
{ nominee: "", description: "", nominatedby: "" }
]);
const inputForm = (choiceForm) => {
alert("Hello");
};
return (
<div className="App">
<h1>Form</h1>
<form>
{createForm.map((field, index) => {
<div key={index}>
<input name="nominee" type="text" />
</div>;
})}
<input value="Create Form" type="button" onClick={inputForm} />
</form>
</div>
);
}
https://codesandbox.io/s/wonderful-wilson-hmts5?file=/src/App.js:0-311
Here is an example of creating a form as you asked.
Adding 48h limit globally (meaning it should persist for all users) requires a server, then you will just need to fetch/update the status. See API and AJAX calls in docs.
const formFields = [
["nominee", "Example"],
["description", "Desc"],
["nominatedby", ""]
];
export default function App() {
const [isFormCreated, setIsFormCreated] = useState(false);
const onClickEnableForm = () => setIsFormCreated(true);
return (
<div className="App">
<h1>Form</h1>
{isFormCreated && (
<form>
{formFields.map(([name, value]) => {
return (
<div key={name}>
<input defaultValue={value} name={name} type="text" />
</div>
);
})}
<input type="submit" />
</form>
)}
{!isFormCreated && (
<input value="Create Form" type="button" onClick={onClickEnableForm} />
)}
</div>
);
}
I am aiming for new tasks to show as user clicks "add task", simple I know, but still learning react.
My goal was to use a ternary operator until its no longer null, and then map through the array each time a user clicks add task.
Issue:
I believe the renderTasks array isn't set by the time it tries to map over it, I get an error...
renderTasks.map is not a function
Is there a way I could utilize the useEffect for what I am trying to do, or any better ideas that could help? Thanks
Here's the code snippet of App.js
function App() {
const [tasks, setTasks] = useState([]);
const [renderTasks, setRenderTasks] = useState(null);
const handleAddTask = () => {
setRenderTasks(tasks);
};
const handleOnChange = (e) => {
setTasks({
...tasks,
[e.target.name]: e.target.value,
});
};
return (
<>
<div className="overview">
<label className="my-todos">My Todos</label>
<div className="input-div">
<div className="input-container">
<label className="title-desc">Title</label>
<input
name="title"
onChange={handleOnChange}
className="input-values"
type="text"
></input>
</div>
<div className="input-container">
<label className="title-desc">Description</label>
<input
name="description"
onChange={handleOnChange}
className="input-values"
type="text"
></input>
</div>
<button onClick={handleAddTask} className="add-task">
Add Task
</button>
</div>
{renderTasks !== null ? (
<ul>
{renderTasks.map((x) => {
return <li>{x.title - x.description}</li>;
})}
</ul>
) : null}
</div>
</>
);
}
export default App;
There were few issues in your implementation like how you destructing tasks, trying to access an object as an array and abusing the useState. You don't need useEffect or two useState to do the trick.
import React from "react";
import React, { useState } from 'react';
import "./style.css";
function App() {
const [tasks, setTasks] = useState([]);
const task = {};
const handleOnChange = (e) => {
task[e.target.name] = e.target.value;
};
const onClickHandler = (e)=>{
(task.title) && setTasks( [...tasks, task]);
}
return (
<>
<div className="overview">
<label className="my-todos">My Todos</label>
<div className="input-div">
<div className="input-container">
<label className="title-desc">Title</label>
<input
name="title"
onChange={handleOnChange}
className="input-values"
type="text"
></input>
</div>
<div className="input-container">
<label className="title-desc">Description</label>
<input
name="description"
onChange={handleOnChange}
className="input-values"
type="text"
></input>
</div>
<button onClick={onClickHandler} className="add-task">
Add Task
</button>
</div>
<ul>
{tasks.map((x) => {return <li>{x.title} - {x.description}</li> })}
</ul>
</div>
</>
);
}
export default App;
Even though you are initialising tasks to be an array, in handleOnChange you are setting it to an Object like this -
setTasks({
...tasks,
[e.target.name]: e.target.value,
});
This same tasks object you are trying to set for renderTasks in handleAddTask. So renderTasks is assigned to an Object and not an array and only arrays have map function and hence you are facing the issue renderTasks.map is not a function error
Try doing
Object.keys(renderTasks).map((x) => {
return <li>{x.title - x.description}</li>;
})