In the following code there are three questions with some checkboxes. There is only one form and the questions change content based on a count state. The values of the chosen checkboxes is saved and displayed in another component.
When I click on the next button I would like to get the new question and the checkboxes to reset. Currently if I check one of the checkboxes and click next, the checkbox still remains checked for the next question. Is it possible to remove the checked state on button click in this scenario?
import React from "react";
import questionsData from "../questions-data";
function AddQuestions({ onAddTwo }) {
const [userinfo, setUserInfo] = React.useState({
options: [],
response: [],
});
const handleChange = (e) => {
// Destructuring
const { value, checked } = e.target;
const { options } = userinfo;
checked === true
? setUserInfo({
options: [...options, value],
response: [...options, value],
})
: setUserInfo({
options: options.filter((e) => e !== value),
response: options.filter((e) => e !== value),
});
};
///submits to list
const [count, setCount] = React.useState(0);
const data = questionsData.data.option;
const ask = data[count].ask;
const one = data[count].one;
const two = data[count].two;
const three = data[count].three;
const onSubmitTwo = (e) => {
e.preventDefault();
console.log("clicked")
const daas = userinfo.response;
!daas.length ? console.log("empty") : onAddTwo({ daas });
!daas.length ? alert("please add task") : setCount(count + 1);
};
//button func
const stylesNext = {
display: count > 2 ? "none" : " ",
};
return (
<>
<form>
<div className="one">
<legend>{ask}</legend>
<input className= "check--input"
type="checkbox"
name= "option"
value={one}
checked ={choice}
onChange={handleChange} />
<label htmlFor="check--input">{one}</label>
<input className="check--input"
type="checkbox"
name="option"
value={two}
onChange={handleChange} />
<label htmlFor="check--input">{two}</label>
<input className="check--input"
type="checkbox"
name="option"
value={three}
onChange={handleChange} />
<label htmlFor="check--input">{three}</label>
</div>
<div className="control--btns">
<button className="next--btn" onClick={onSubmitTwo} style={stylesNext}>
{count === 2 ? "Submit" : "Next"}
</button>
</div>
</form>
);
}
export default AddQuestions;
```
Related
i'm mapping multiple buttons and want to select the 1st button to be checked on render and that value is shown on render
this is the axios get
const [productData, setProductData] = useState([]);
const [size, setSize] = useState([]);
const [choice, setChoice] = useState("");
useEffect(() => {
const checkId = parseInt(window.location.href.slice(-1));
axios.get(`http://localhost:5000/products?id=${checkId}`)
.then((response) => {
setProductData(response.data[0]);
setSize(response.data[0].size);
setChoice(response.data[0].size[0].calories);
});
}, []);
here is the button map
const GetSize = () => {
return size.map((val, i) => {
return (
<>
<div>
<input
onClick={(e) => {
setChoice(val.calories);
}}
defaultChecked={i == 0}
type="radio"
/>
<p>{val.option}</p>
<p>{val.cup}</p>
</div>
</>
);
});
};
and have to show a value on render here
<div >
<h1>{choice === 0 ? "" : choice}</h1
<div>
<h1>Size options</h1>
</div>
<div >
<form>
<GetSize />
</form>
</div>
</div>
on render the {choice} doesn't show and only shown whenever i clicked on the radio button.
how do i make it so {choice} waits until setChoice runs
and also, the button needs to be clicked twice for it to be rendered chosen, but one click on the button is enough to make {choice} rendered
possible solution for the first part of the question
useEffect(() => {
const checkId = parseInt(window.location.href.slice(-1));
axios.get(`http://localhost:5000/products?id=${checkId}`)
.then((response) => {
setProductData(response.data?.[0] ?? []);
const responseSize = response.data?.[0]?.size ?? []
setSize(responseSize);
// setting the default choice
setChoice(responseSize.[0]?.calories ?? "")
});
}, []);
I have stomped on a problem that i don't know how to resolve.
I have a react-select input that passes a selected value to another select input.
When a user clicks on submit button then i have to display an array of every selector input that the user has selected as a list of items and then the form should reset all select values.
For this, i have tried submitting to an array but it only shows one item from all selectors and form doesn't reset its values.
Here is a sandbox link
https://codesandbox.io/s/awesome-carson-i99g8p?file=/src/App.js
How can I archive this I have tried everything but I could not figure out how can i archive this functionality.
Ok. First tricky thing of react-select is, the value you assign to the component must be an object with label and valueproperties, not just the value. Meaning, when handling change events, you should set the state using the full event object.
This is the code mostly fixed:
import React, { useState, useEffect } from "react";
import Select from "react-select";
const options = [
{ value: "0", label: "0" },
{ value: "1", label: "1" },
{ value: "2", label: "2" }
];
const options2 = [
{ value: "Before Due Date", label: "Before Due Date" },
{ value: "After Due Date", label: "After Due Date" }
];
const App = (props) => {
const [numOfDays, setNumOfDays] = useState('');
const [beforeDueDate, setBeforeDueDate] = useState('');
const [items, setItems] = useState([]);
const [reminders, setReminders] = useState([]);
const submit = (event) => {
event.preventDefault(); // <-- prevent form submit action
const obj = {};
obj.id = reminders.length + 1;
obj.numOfDays = numOfDays.value;
obj.beforeDueDate = beforeDueDate.value;
setReminders((items) => [...items, obj]); // <-- update arr state
setBeforeDueDate("");
setNumOfDays("");
};
function numOfDaysHandle(event) {
// const numOfDays = event.value;
setNumOfDays(event);
setItems((items) => [...items, items]);
}
function beforeDueDateHandle(event) {
// const value = event.value;
setBeforeDueDate(event);
}
const removeReminder = (id) => {
setReminders(reminders.filter((item) => item.id !== id));
};
return (
<>
<form>
<div>
{reminders.map((item, index) => (
<div key={index}>
<div>
<span>
{item.numOfDays} days {item.beforeDueDate}
</span>
<button onClick={() => removeReminder(item.id)}>
removeItem
</button>
</div>
</div>
))}
</div>
<div>
<Select
options={options}
value={numOfDays}
id="numOfDays"
placeholder="Days"
isSearchable={false}
//onChange={numOfDaysHandle}
onChange={numOfDaysHandle}
/>
<Select
options={options2}
value={beforeDueDate}
id="beforeDueDate"
placeholder="Before Due Date"
isSearchable={false}
onChange={beforeDueDateHandle}
/>
</div>
{items.map((item, index) => (
<div key={index}>
<Select
options={options}
value={item.numOfDays}
id="numOfDays"
placeholder="Days"
isSearchable={false}
onChange={numOfDaysHandle}
/>
<Select
options={options2}
value={item.beforeDueDate}
id="beforeDueDate"
placeholder="Before Due Date"
isSearchable={false}
onChange={beforeDueDateHandle}
// onClick={() => setItems((items) => [...items, items])}
/>
</div>
))}
<button
onClick={submit}
//disabled={!numOfDays}
>
Set Reminder
</button>
</form>
</>
);
};
export default App;
Please see if you can move forward now, I could not understand what you want exactly with the array of <Select /> elements.
I want to disable the submit button on the form if the user enters a value that already exists in the task list.
'Todos' is the array that stores the list and I used 'some' to check if the input value is equal to some title. However, it doesn't work.
CODE
const [disable, setDisable] = useState(false);
const onFormSubimit = (event) => {
event.preventDefault();
if (!editTodo) { //mudar depois a condição
setTodos([...todos, {
id: uuidv4(),
title: input,
completed: false
}]);
setInput("");
} else {
updateTodo(input, editTodo.id, editTodo.completed);
}
}
const handleInputChange = (event) => {
let inputValue = event.target.value;
setInput(inputValue);
getInputValue(inputValue);
}
const getInputValue = (inputValue) => {
let some = todos.some(item => item.title === inputValue);
if (some!=disable) {
setDisable(true);
}
}
return (
<form onSubmit={onFormSubimit}>
<input type='text' name='text' placeholder='Insira o nome da tarefa' className='task-input' value={input} onChange={handleInputChange} required></input>
<button type='submit' className='button-add' disabled={getInputValue} >{editTodo ? 'Alterar' : 'Adicionar'}</button>
</form>
);
}
Your button state is dependent on input (the variable set by setInput) and todos. So the best way to handle this is via an useEffect with a dependency array.
useEffect(() => {
// Array.some returns a boolean
setDisable(todos.some(item => item.title === input))
}, [todos, input]);
Your button code
<button type='submit' className='button-add' disabled={disable} >{editTodo ? 'Alterar' : 'Adicionar'}</button>
You can also directly use this logic in button like below. In this case there is no need of useEffect
<button type='submit' className='button-add' disabled={todos.some(item => item.title === input)} >{editTodo ? 'Alterar' : 'Adicionar'}</button>
First, change your button with the code below (as it should be disabled ={disable}, not disabled={getInputValue}). And getInputValue as following.
<button type='submit' className='button-add' disabled={disable} >{editTodo ? 'Alterar' : 'Adicionar'}</button>
const getInputValue = (inputValue) => {
if (todos.some((item) => item.title === inputValue)) {
setDisable(true);
} else {
setDisable(false);
}
};
I have a bunch of checkboxes with the following markup
<input type='checkbox' data-id='123' data-label='abc' ref={checkboxRef} />
<input type='checkbox' data-id='456' data-label='xyz' ref={checkboxRef} />
And a state which is initially set as an empty array
const [contacts, setContacts] = useState([])
What I want to do is update the state with an object of a checkbox's data based on whether it's checked or not. If checked, it's data is to be added to the state and if unchecked, remove it.
Expected state after a checkbox is checked
[
{ id: '123', label: 'abc' }
]
I've used a ref for now to the input and getting the data of it but can't figure out how to go about updating the state.
const handleToggle = () => {
setIsChecked(prevState => !isChecked)
const id = checkboxRef.current.getAttribute('data-id')
const label = checkboxRef.current.getAttribute('data-label')
}
I have solved it. Check it here.
https://codesandbox.io/s/affectionate-fermi-f6bct
Full code hereby is
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [contacts, setContacts] = useState([]);
const ref1 = React.createRef();
const ref2 = React.createRef();
const handleClick = (ref) => {
const id = ref.current.getAttribute("data-id");
const label = ref.current.getAttribute("data-label");
if (contacts.map((e) => e.id).includes(id)) {
setContacts(contacts.filter((e) => e.id !== id));
} else {
setContacts([...contacts, { id, label }]);
}
console.log(contacts);
};
return (
<div className="App">
<input
type="checkbox"
data-id="123"
data-label="abc"
ref={ref1}
onClick={() => {
console.log("hi");
handleClick(ref1);
}}
/>
<input
type="checkbox"
data-id="456"
data-label="xyz"
ref={ref2}
onClick={() => handleClick(ref2)}
/>
</div>
);
}
I'm trying to enable button if both the checkboxes are checked, I have nonworking stackblitz link
I have added the only crux of functionality. Please look into the link for the nonworking demo
import React, { useState } from 'react';
import { render } from 'react-dom';
function App (){
const [checked, toggleCheckbox] = useState({ checkbox1: false, checkbox2: false, disabled: true });
const getDisabled = (state) => {
if (state.checkbox1 || state.checkbox2) {
return false;
} else if (!state.checkbox1 && !state.checkbox2) {
return true;
} else {
return true;
}
};
const handleCheckbox = (checkbox) => {
toggleCheckbox({
...checked,
[checkbox]: !checked[checkbox],
disabled: getDisabled(checked)
});
console.log(checked);
};
const checkDisable = checked.disabled ? 'disabled' : ''
return (
<div>
<div>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox('checkbox1')}
checked={checked.checkbox1}
/>
<span className="black-text">Checkbox1</span>
</label>
</div>
<div>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox('checkbox2')}
checked={checked.checkbox2}
/>
<span className="black-text">checkbox2</span>
</label>
</div>
<div>
<a className={checkDisable} href="#!">
Next Step
</a>
</div>
</div>
);
}
render(<App />, document.getElementById('root'));
The functionality should be as follows:
The button should be enabled only if both the checkboxes are checked
On unchecking anyone checkboxes it should disable the button
You can simply check the state of both checkbox values.
const isDisabled = !(checked.checkbox1 && checked.checkbox2)
const checkDisable = isDisabled ? 'disabled' : ''
No need to change elsewhere.
Forked stackblitz link.
https://stackblitz.com/edit/react-jscqwr?file=index.js
Answer to the comment.
Hey, that worked! I could see in the log that the state one step below the updated state for an instance after clicking in the first checkbox { checkbox1: false, checkbox: false, disabled: false } after clicking the second checkbox the log { checkbox1: true, checkbox: false, disabled: false }
The reason you are seeing outdated state is because the state updator toggleCheckbox batches the update, thus you'd need to check for the updated status in an effect, which monitors the updated status.
Dynamic number of checkboxes.
I've updated the stack to track dynamic number of checkboxes.
New fork~
https://stackblitz.com/edit/react-pl1e2n
Looks like this.
function App() {
const length = 6;
1️⃣ Generate the initial checkbox states - this prevents un/controlled component error.
const initialCheckboxes = Array
.from({ length }, (_, i) => i + 1)
.reduce((acc, id) => (acc[id] = false, acc), {})
const [checked, toggleCheckbox] = useState(initialCheckboxes);
const [isDisabled, setIsDisabled] = useState(false)
const handleCheckbox = id => {
toggleCheckbox(previous => ({
...previous,
[id]: !previous[id]
}));
};
2️⃣ Update the disable state when the checkbox is selected.
useEffect(() => {
👇 Enable when all checkboxes are not checked - 😅
setIsDisabled(!Object.values(checked).every(_ => !!_))
}, [checked])
3️⃣ Dynamically generate checkboxes
const checkboxElements = Array.from({ length }, (_, i) => i + 1)
.map(id => (
<div key={id}>
<label>
<input
type="checkbox"
className="filled-in"
onChange={() => handleCheckbox(id)}
checked={checked[id]}
/>
<span className="black-text">Checkbox{id}</span>
</label>
</div>
))
return (
<div>
{checkboxElements}
<div>
<a className={isDisabled ? 'disabled' : ''} href="#!">
Next Step
</a>
</div>
</div>
);
}