Handling state with multiple checkboxes in React Native - javascript

I have a simple form with two checkboxes for someone to choose one or the other i.e Yes or No not both. Am using the React-native-element toolkit as shown below.
export default class CheckerForm extends React.Component {
state = {
checked: false,
}
handleYesCheck =() => {
this.setState({checked: !this.state.checked})
}
handleNoCheck =() => {
this.setState({checked: !this.state.checked})
}
render(){
const { checked } = this.state
return (
<View>
<CheckBox
center
title='Yes'
checked={checked}
onPress={this.handleYesCheck}
/>
<CheckBox
center
title='No'
checked={checked}
onPress={this.handleNoCheck}
/>
<View>
I want to capture and modify the state of the checkboxes but when I click one of the checkboxes I modify the state of the other i.e both will be checked and unchecked. How can I modify the states of the checkboxes independently such that when I click on Yes, No is unchecked and vice versa? Generally what is the best way to capture the state so that I can use it.

What you can do is have a array of checkboxes, and save in the state the index of the checked one.
state = {
checkedId: -1,
checkboxes: [{
id: "yes",
title: "Yes"
}, {
id: "no",
title: "No"
}]
}
handleCheck = (checkedId) => {
this.setState({
checkedId
})
}
render() {
const {
checkboxes,
checkedId
} = this.state
return ( <
View > {
checkboxes.map(checkbox => ( <
CheckBox center key = {
checkbox.id
}
title = {
checkbox.title
}
checked = {
checkbox.id == checkedId
}
onPress = {
() => this.handleCheck(checkbox.id)
}
/>
)
} <
View >
)
}
This way you can also handle more than two checkboxes and also know which one is checked by the index.

Related

how to add dinamically components with data, on objects list with react js

I have a component list, in this case is a MUI chips, which has some props (label, callback) and I need to add them to my list when onClick event is triggered.
The chip is going to have a label, which is a name selected from a dropdown menu.
I found quite difficult to have a unique chip with the name selected.
//my components list
const [chipList, setChip] = useState([{ chip: "" }]);
const addNewCategory = () => {
if (chipList.length < 5) {
setChip([...chipList, { chip: "" }]);
}
};
//my map to render the component
{chipList.map((widget, index) => (
<CategoryChip key={index} label={subCategory} onDelete={() => handleDelete(index)} />
))}
I am quite sure I have to pass the label inside my useState([{ chip: "" }]) and yes I know, for the moment my chips has all same name because of the label attribute
You don't need to map() your chipList if your intent is to only show one. The one that is selected.
I'm assuming your subCategory state or prop is the chip info that you chose from the dropdown.
You can use findIndex() to show CategoryChip related with that choice.
export default YourComponent = () => {
const [chipList, setChip] = useState([{ chip: "" }]);
const addNewCategory = () => {
if (chipList.length < 5) {
setChip([...chipList, { chip: "" }]);
}
};
...
const renderSelectedChip = () => {
const foundChipIndex = chipList.findIndex(el => el.chip === subCategory);
// I checked for subCategory just to make sure that empty string wasn't a selectable option, but you can remove it if you want
if (!subCategory || foundChipIndex === -1) {
return <></>;
}
return <CategoryChip label={subCategory} onDelete={() => handleDelete(foundChipIndex)} />
))} />
}
return (
<>
...
{renderSelectedChip()}
</>
)
}

How to handle checked in input type='checkbox' in React?

I have a group of checkboxes, some of them are pre-checked and some will be updated from the user. problem is the checkboxes render fine in initial render but they don't change on click. The value of 'checked' gets updated on change (onChange)
<input
type = 'checkbox'
style = {{margin : '0'}}
checked = {this.state[elem]}
value = {elem}
onChange = {this.checked}
/> {elem}
and in the checked method
checked = e => {
this.setState({
[e.target.value] : !this.state[e.target.value]
})
}
You haven't shared with us how you are generating these inputs, but the primary issue has to do with using a single source of truth for all your inputs. You want to give each input, particularly the object that corresponds to that input, their own checked-state.
Considering the following example with working codesandbox: https://codesandbox.io/s/relaxed-feynman-1thb8
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const arr = [
{ val: "Cat", checked: false },
{ val: "Dog", checked: true },
{ val: "Turtle", checked: false }
];
class App extends React.Component {
state = {
arr: arr
};
handleCheck = e => {
const arrCopy = [...this.state.arr];
const itemToUpdate = arrCopy.find(item => item.val === e.target.value);
itemToUpdate.checked = !itemToUpdate.checked;
this.setState({
arr: arrCopy
});
};
createInputs = () => {
const { arr } = this.state;
return arr.map(elem => {
return (
<div>
<input
type="checkbox"
style={{ margin: "0" }}
checked={elem.checked}
value={elem.val}
onChange={this.handleCheck}
/>
{elem.val}
</div>
);
});
};
render() {
return <div>{this.createInputs()}</div>;
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
In the above code, we organize your state-data as in array of objects, making it easier for you to render the mark-up AND keep track of the checked state of each input. Then in the handleCheck function, we identify the checked item, find its corresponding object in the array and toggle the checked state of that item.
Set input's name property to property equivalent to that of state's key. Also your way of accessing object's key as this.state[elem] is inappropriate as elem is not a variable(that should contain string as state's key).
I have prepared codesandbox for use case. Here is codesandbox link for the example : https://codesandbox.io/embed/clever-colden-2ydb6
Updated code:
checked = e => {
const checked = e.target.checked;
const name = e.target.name;
this.setState({
[name]: checked
});
};
render() {
return (
<div>
<input
type="checkbox"
style={{ margin: "0" }}
// set name prop to equivalent to state's property
name="elem"
// either use - this.state['elem'] or this.state.elem
checked={this.state.elem}
// value = {elem} no need of this
onChange={this.checked}
/>
Is checked : {this.state.elem ? "yes" : "no"}
</div>
);
}

how to populate options for a react select by fetching values from an api to be visible when you click on the select box?

I am using react-select for drop downs in my application. Below is my requirement.
Select a value from the drop down for the first Select component(second Select is not rendered yet).
Basing on the selected value fetch the options for second Select component and render the second Select box.
Click in the text area of the second Select.
What is happening : I see No Options as the default drop down. I can
see the values from the API only when I type something in the box and
that matches the default filter criteria.
What I want to happen : It
should display the values that we fetched from the API call.
const options = [{ label: "first", value: "first" }];
let options1 = [];
async function copyOptionsForAsync() {
let response = await fetch("https://jsonplaceholder.typicode.com/todos");
let data = await response.json();
data.forEach(element => {
let dropDownEle = { label: element["title"], value: element };
options1.push(dropDownEle);
});
}
class App extends React.Component {
constructor() {
super();
this.state = {
isSelected: false
};
}
handleOnchange = () => {
this.setState({ isSelected: true });
copyOptionsForAsync();
console.log(options1);
};
render() {
return (
<div className="App">
<Select
name="option"
options={options}
onChange={this.handleOnchange}
/>
{this.state.isSelected ? <App1 /> : null}
</div>
);
}
}
class App1 extends React.Component {
render() {
return (
<div className="App">
<Select name="options2" options={options1} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
This is the link to codesandbox page. Can any one tell me how will I be able to display the options once I click on the select box.
'App1' is rendering before you actually get the data. One way to fix this is to wait for the data to be fetched then render 'App1', like this:
handleOnchange = async () => {
await copyOptionsForAsync();
this.setState({ isSelected: true });
};
Working example in codesandbox: https://codesandbox.io/s/m6wr8zvjj

How to handle multiple radio button groups in one component in reactjs?

I'm trying to send list of selected radio button ids from multiple radio button groups on clicking send button,
My problem:
I am getting selected radio button from backend , then I should be able to change the radio button and send back to backend. but when I try to change the radio button it is not working.
What I did not understand:
How to handle the on change function, normally on change we can change the state but to change the state on load we should grab the values radio buttons. Finally I got struck here, not understanding how to move forward.
Here is the wireframe and code snippet:
function CardsList(props) {
const cards = props.cards;
return (
<div>
{cards.map((card, idx) => (
<div>
{card.cardName}
{
card.options.map((lo,idx) => (
<li key={idx}>
<input
className="default"
type="radio"
name={card.cardName}
checked={lo.selected}
/>))
}
<div>
))}
</div>
);
}
//array of cards coming from the backend
const cards = [
{cardName:'card1',options:[{radioName:'card1-radio1',selected:'true'},
{radioName:'card1-radio2',selected:'false'}]},
{cardName:'card2',options:[{radioName:'card2-radio1',selected:'true'},
{radioName:'card2-radio2',selected:'false'}]}
];
ReactDOM.render(
<CardsList cards={cards} />,
document.getElementById('root')
);
<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="root"></div>
You can use an object as a lookup table that holds the group names as keys.
On each change you will need to find the relevant group with the relevant option and set the new state accordingly.
Important! - one thing to notice here, is that i changed the type of the selected property from a String to a Boolean. this will let me handle the conditions like this:
<input checked={option.selected} />
If you can't change it to a Boolean then you will need to handle the condition like this:
<input checked={option.selected === 'true'} />
Here is a running example:
//array of cards coming from the backend
const data = [
{
cardName: 'card1', options: [{ radioName: 'card1-radio1', selected: true },
{ radioName: 'card1-radio2', selected: false }]
},
{
cardName: 'card2', options: [{ radioName: 'card2-radio1', selected: true },
{ radioName: 'card2-radio2', selected: false }]
}
];
class CardsList extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: []
};
}
componentDidMount() {
setTimeout(() => {
// mimic an async server call
this.setState({ cards: data });
}, 1000);
}
onInputChange = ({ target }) => {
const { cards } = this.state;
const nexState = cards.map(card => {
if (card.cardName !== target.name) return card;
return {
...card,
options: card.options.map(opt => {
const checked = opt.radioName === target.value;
return {
...opt,
selected: checked
}
})
}
});
this.setState({ cards: nexState })
}
onSubmit = () => { console.log(this.state.cards) };
render() {
const { cards } = this.state;
return (
<div>
{
cards.length < 1 ? "Loading..." :
<div>
{cards.map((card, idx) => (
<ul>
{card.cardName}
{
card.options.map((lo, idx) => {
return <input
key={idx}
type="radio"
name={card.cardName}
value={lo.radioName}
checked={!!lo.selected}
onChange={this.onInputChange}
/>
})
}
</ul>
))
}
< button onClick={this.onSubmit}>Print Cards</button>
</div>
}
</div>
);
}
}
ReactDOM.render(<CardsList />, document.getElementById('root'));
<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="root"></div>
The reason why you can't change them is because of their current checked state which you are setting here:
<input
className="default"
type="radio"
name={card.cardName}
checked={lo.selected}
/>
An approach I have used for this exact scenario is storing the component's state (from the server) in my component's state (this.state), passing the state to the element: checked={this.state.isChecked}, and updating the element's state onClick.
Example:
class CardsList extends Component {
constructor(props){
super(props);
this.state = {isChecked: false};
this.inputOnClick = this.inputOnClick.bind(this);
}
//fetch data from server
fetchData(){
fetch('/api')
.then(res => res.json())
//this will be our initial state
.then(res => this.setState(res))
}
componentDidMount(){
this.fetchData();
}
//change radio button state on click
inputOnClick(e){
e.preventDefault();
//invert state value
this.setState((prevState, props) => {isChecked: !prevState.isChecked});
}
render(){
return (
<input
type="radio"
checked={this.state.isChecked}
onClick={this.inputOnClick}
/>
)
}
}
this answer may work with single radio button group , but i am facing
problem with multiple radio buttons with in multiple radio button
groups.if you see the array of cards , how does it know which radio
button group it belongs to.
We can modify the state based on the radio button's name.
Let's save all of your cards in your component's state. I know the cards are retrieved from the server and will be saved using setState but I am writing it like this for visual purposes.
this.state = {cards: [
{ cardName:'card1',
options:[
{radioName:'card1-radio1',selected:true},
{radioName:'card1-radio2',selected:false}
]
},
{ cardName:'card2',
options:[
{radioName:'card2-radio1',selected:true},
{radioName:'card2-radio2',selected:false}
]
}
]}
Now when we click on a radio button, we will use that radio button's name to update the state where it needs to be updated. Since React state needs to be immutable, we will create a deep copy of the state, modify it, and then set the state with it.
inputOnClick(e){
e.preventDefault();
var thisRadioBtn = e.target.name;
//make a deep copy of the state
const stateCopy = JSON.parse(JSON.stringify(this.state.cards));
//go through state copy and update it
stateCopy.forEach(card => {
card.options.forEach(option => {
if(option.radioName === thisRadioBtn){
//invert value
//make sure the values are booleans
option.selected = !option.selected;
}
});
});
//update the components state
this.setState({cards: stateCopy});
}
In June 2022, I'm facing a similar issue with you. My solution is just add tag <form> on both sections with no OnSubmit or action on it.

Checkbox issue oncheck function

Please see the following code at first.
I want the particular checkbox (with id cfc1) to not be shown ticked whenever clicking on it.
I have used the onCheck function there. I'm not finding any way to the particular element be shown unchecked whenever clicked on it. I'm trying using the code -
if(e.currentTarget.id === 'cfc1') {
document.getElementById(e.currentTarget.id).checked = false;
}
but it's not working.
How to do it using the onCheck function?
import React, {Component} from 'react';
import Checkbox from 'material-ui/Checkbox';
class Checkboxes extends Component {
constructor() {
super();
this.state = {
checkids:['cfc0', 'cfc1', 'cfc2', 'cfc3']
};
this.handleCheck = this.handleCheck.bind(this);
this.getElements = this.getElements.bind(this);
}
getElements() {
let arr = [];
this.state.checkids.forEach(function(element) {
arr.push(
<Checkbox
id={element}
onCheck={this.handleCheck}
/>
);
}, this)
return arr;
}
handleCheck(e) {
console.log(e.currentTarget.id);
console.log(e.currentTarget.checked);
}
render() {
return(
<div>
{this.getElements()}
</div>
);
}
}
export default Checkboxes
To get it working for your use case, try having a state variable that maintains the checked information of each element id.
And in the onCheck handler toggle the checkbox for all the boxes except the one desired by setting the state.
WORKING DEMO
class App extends Component {
constructor() {
super();
this.state = {
checkids:{
'cfc0': false,
'cfc1': false,
'cfc2': false,
'cfc3': false
}
};
}
handleCheck(e) {
const checkids = {...this.state.checkids};
checkids[e.target.id] = e.target.id === "cfc1" ? false : !checkids[e.target.id];
this.setState({checkids});
}
getElements() {
let arr = [];
Object.keys(this.state.checkids).forEach(function(element, index) {
arr.push(
<Checkbox
key={index}
id={element}
checked={this.state.checkids[element]}
onCheck={this.handleCheck.bind(this)}
/>
);
}, this)
return arr;
}
render() {
return (
<MuiThemeProvider>
<div>
{this.getElements()}
</div>
</MuiThemeProvider>
);
}
}
You can use this.checked = false via javascript
document.getElementById('cfc1').onclick = function() {
this.checked = false;
}
<label><input type="checkbox" id="cfc1">Click</label>

Categories

Resources