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
}
Related
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>
);
}
Updated CodeSandbox link here
The Add transaction button is not rendering the transaction list in transaction history container
This piece of code {transaction && transaction.map(trans).... is rendering the app UI but the Add transaction button is not generating the Transaction component dynamically in transaction history container}
import React from 'react';
const AddTransaction =
({item,amount,setItem,setAmount,transaction,setTransaction})
=> {
const onSubmit = (e) => {
e.preventDefault();
setTransaction([...transaction,
{
text: item,
amount: amount,
id: Math.floor(Math.random()*1000),
}
] );
setItem('');
setAmount('');
}
return (
<div className='addtransaction-container'>
<div className='add-trans-header'>
<h4>Add New Transaction</h4>
</div>
<form>
<div className="form-control">
<label htmlFor="text">Text</label>
<input type="text" value={item}
onChange={(e) => setItem(e.target.value)}
placeholder="Enter text..." />
</div>
<div className="form-control">
<label htmlFor="amount"
>Amount <br />
(negative - expense, positive - income)
</label>
<input type="number" value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter amount..." />
</div>
<button type='button' onClick={onSubmit}
value='submit'
className="btn">
Add transaction
</button>
</form>
</div>
);
}
export default AddTransaction;
The map function is not rendering the Transaction
component in TransactionList.js file
import React from 'react'
import './App.css';
import Transaction from './Transaction.js';
const TransactionList = ({text,transaction,amount}) => {
return (
<div className='transactionlist-container'>
<div className='transactionlist-header-container'>
<h4>
Transaction History
</h4>
</div>
<ul>
<li>
{ transaction.map(trans =>
<Transaction
amount={transaction.amount}
text={transaction.text}
key={transaction.id} />
)}
</li>
</ul>
</div>
)
}
export default TransactionList;
My Transaction.js file have a ul list with the input text and amount but the component is not rendering in the app UI.
import React from 'react'
const Transaction = ({transaction,text,amount}) => {
return (
<div className='transaction'>
{text}<span>{amount}</span>
</div>
)
}
export default Transaction;
I have recreated the app, which is working without any issue.
Here is the link to the working demo: StackBlitz
import React, { useState, useEffect } from "react";
import TransactionList from "./TransactionList";
import AddTransaction from "./AddTransaction";
const App = () => {
const [transaction, setTransaction] = useState([]);
const handleTransaction = value => {
setTransaction([...transaction, value]);
};
const expenseList = transaction.filter(trans => Number(trans.amount) < 0);
const expense = expenseList.reduce(
(acc, curr) => acc + Number(curr.amount),
0
);
const amountList = transaction.filter(trans => Number(trans.amount) > 0);
const amount = amountList.reduce((acc, curr) => acc + Number(curr.amount), 0);
useEffect(() => {
console.log("From app:", transaction);
}, [transaction]);
return (
<div className="transactionlist-container">
<div>
<span>income: {JSON.stringify(amount)}</span>{" "}
<span> total expense: {JSON.stringify(expense)}</span>
<span> balance: {amount + expense}</span>
</div>
<TransactionList transaction={transaction} />
<AddTransaction
transaction={transaction}
handleTransaction={handleTransaction}
/>
</div>
);
};
export default App;
import React from "react";
import Transaction from "./Transaction";
const TransactionList = ({ transaction }) => {
console.log("from tl:", transaction);
return (
<div className="transactionlist-container">
<div className="transactionlist-header-container">
<h4>Transaction History</h4>
</div>
{transaction.map(trans => (
<Transaction amount={trans.amount} text={trans.text} key={trans.id} />
))}
</div>
);
};
export default TransactionList;
import React from "react";
const Transaction = ({ text, amount }) => {
return (
<div className="transaction">
{text}
<span>{amount}</span>
</div>
);
};
export default Transaction;
import React,{useState} from "react"
const AddTransaction =
({handleTransaction})
=> {
const [item,setItem] = useState("")
const [amount, setAmount] = useState(0)
const onSubmit = (e) => {
e.preventDefault();
handleTransaction(
{
text: item,
amount: amount,
id: Math.floor(Math.random()*1000),
}
);
setItem('');
setAmount('');
}
return (
<div
className="inputBox"
>
<div className='add-trans-header'>
<h4>Add New Transaction</h4>
</div>
<form>
<div className="form-control">
<label htmlFor="text">Text</label>
<input type="text" value={item}
onChange={(e) => setItem(e.target.value)}
placeholder="Enter text..." />
</div>
<div className="form-control">
<label htmlFor="amount"
>Amount <br />
(negative - expense, positive - income)
</label>
<input type="number" value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Enter amount..." />
</div>
<button type='button' onClick={onSubmit}
value='submit'
className="btn">
Add transaction
</button>
</form>
</div>
);
}
export default AddTransaction;
The Error Message:
If i dont use the Inputs inside div then it works perfectly but when i use Input inside div it shows me this error.
I wanted to keep the hook related stuff separated so it look clean.
why does it only works when its not inside a div?
Login.tsx
import { useHistory } from "react-router-dom";
import { useForm } from "react-hook-form";
import useAuth from "./../hooks/useAuth";
import { Form, Input } from "../components/FormGroup";
import MacNav from "../components/MacNav";
import { loginActionUrl } from "./../services/ApiLinks";
import {
fetchPostResopnse,
successPopUp,
errorPopUp,
} from "./../services/FormHelper";
type Tinputs = {
username: string;
password: string;
};
function Login() {
const auth = useAuth();
const history = useHistory();
const methods = useForm<Tinputs>();
const onSubmit = async (data: Tinputs) => {
const result = await fetchPostResopnse(loginActionUrl, data);
if (result.isAuth) {
successPopUp("Credentials Matched", () => {
auth.signIn(result);
history.push("/admin/dashboard");
});
} else {
errorPopUp("Credentials Does Not Matched");
}
};
return (
<div>
<MacNav />
<div className="section-secondary">
<div className="container">
<div className="contact-form-wrapper">
<div className="title-lg text-center">Enter Your Credentials</div>
<Form formMethods={methods} handler={onSubmit} submitBtn="Submit">
{/*If i dont use Input inside div it works*/}
<div>
<Input name="username" rule={{ required: true }} />
</div>
<Input name="password" rule={{ required: true }} />
</Form>
</div>
</div>
</div>
</div>
);
}
export default Login;
I have wrote the form components here.
FormGroup.tsx
import React from "react";
const Form = ({ children, formMethods, handler, submitBtn }: any) => {
return (
<form onSubmit={formMethods.handleSubmit(handler)}>
{React.Children.map(children, (child) => {
return child.props.name ? (
<div>
{React.createElement(child.type, {
...{
...child.props,
register: formMethods.register,
key: child.props.name,
},
})}
{child.props?.rule && formMethods.errors[child.props.name] && (
<div className="text-danger">
*
{formMethods.errors[child.props.name].message
? formMethods.errors[child.props.name].message
: `${child.props.name} is required`}
</div>
)}
</div>
) : (
child
);
})}
{submitBtn && <button type="submit">{submitBtn}</button>}
</form>
);
};
const Input = ({ register, name, label, rule, ...rest }: any) => {
label = label ? label : name?.charAt(0).toUpperCase() + name?.slice(1);
return (
<div>
<label htmlFor={name}>{label}</label>
<input name={name} ref={register(rule)} {...rest} />
</div>
);
};
const Textarea = ({ register, name, label, rule, ...rest }: any) => {
label = label ? label : name?.charAt(0).toUpperCase() + name?.slice(1);
return (
<div>
<label htmlFor={name}>{label}</label>
<textarea name={name} ref={register(rule)} {...rest}></textarea>
</div>
);
};
const SubmitButton = ({ name, ...rest }: any) => {
return (
<button type="submit" {...rest}>
{name}
</button>
);
};
export { Form, Input, Textarea, SubmitButton };
[1]: https://i.stack.imgur.com/PvEUA.png
Hello according to your code, what happened it's expected
the div doesn't have name so according to this code
{React.Children.map(children, (child) => {
return child.props.name ? (
<div>
{React.createElement(child.type, {
...{
...child.props,
register: formMethods.register,
key: child.props.name,
},
})}
{child.props?.rule && formMethods.errors[child.props.name] && (
<div className="text-danger">
*
{formMethods.errors[child.props.name].message
? formMethods.errors[child.props.name].message
: `${child.props.name} is required`}
</div>
)}
</div>
) : (
child
);
})}
And the below child
<div>
<Input name="username" rule={{ required: true }} />
/div>
The Input component will be rendrered without register prop, so when it will try to call it here, however it's value is undefined, what will cause an error
ref={register(rule)}
I suggest to create a new component
const InputWithDiv = (props) => (
<div>
<Input rule={{ required: true }} {..props} />
/div>
);
and use it like below
<Form formMethods={methods} handler={onSubmit} submitBtn="Submit">
<InputWithDiv name="username" />
<Input name="password" rule={{ required: true }} />
</Form>