I am just started on react and I have a challenge with implementing dynamic checkboxes. I have the checkbox items in a firestore collection and fetch them as an array which I store into something that looks like this:
const checkboxes = [
{
name: 'check-box-1',
key: 'checkBox1',
label: 'Check Box 1',
id: 'first',
value: false
},
{
name: 'check-box-2',
key: 'checkBox2',
label: 'Check Box 2',
id: 'second',
value: true
},
{
name: 'check-box-3',
key: 'checkBox3',
label: 'Check Box 3',
id: 'third',
value: false
},
{
name: 'check-box-4',
key: 'checkBox4',
label: 'Check Box 4',
id: 'fourth',
value: false
},
];
My form is in a class component and I render it like this
class CheckIn extends Component {
state = {
data1: ''
}
render() {
return(
<div>
{
checkboxes && checkboxes
.map(checkbox => {
return(
<div className="checkbox-area" key={checkbox.id}>
<label htmlFor={ checkbox.id }>
<input type="checkbox"
name="check-box"
id={checkbox.id}
value = {checkbox.value}
onChange = {this.handleCheck}
className='filled-in' />
<span>{checkbox.label}</span>
</label>
</div>
)
})
}
</div>
)
}
}
I am not sure what to do in my handleCheck in order for the form to update state as true if it is checked and false it it is unchecked. For now, this only updates the checked ones and sends 'undefined'
handleCheck = (e) => {
this.setState({
[e.target.id] : true
})
}
Please help. Thanks
For checkbox type input, the value is checked not value.
This should work for you:
<div className="checkbox-area" key={checkbox.id}>
<label htmlFor={ checkbox.id }>
<input type="checkbox"
name="check-box"
id={checkbox.id}
checked={checkbox.value}
onChange={this.handleCheck}
className='filled-in' />
<span>{checkbox.label}</span>
</label>
</div>
handleCheck = e => {
this.setState({
[e.target.id]: e.target.checked
})
}
Based on your needed in your comment on #ulou answer post
You need to set all checkboxs state false first after component is mounted
class CheckIn extends Component {
constructor() {
super();
state = {
data1: ''
}
}
componentdidmount(){
checkboxes.map(item => {
this.setState({
[item.id]: false
})
}
}
render() {
return(
<div>
{ checkboxes && checkboxes
.map(checkbox => {
return(
<div className="checkbox-area" key={checkbox.id}>
<label htmlFor={ checkbox.id }>
<input type="checkbox"
name="check-box"
id={checkbox.id}
value = {checkbox.value}
onChange = {this.handleCheck}
className='filled-in' />
<span>{checkbox.label}</span>
</label>
</div>
)
})
}
</div>
)
}
}
Related
I have rendered a list of checkboxes and i am trying to setup an onChange which tracks the selected input and turns the value to true. But i keep getting an error message and also warning with needing a unique key even though i am passing the index.
This is the CodeSandbox
Please check this complete Code:-
import React from "react";
import "./styles.css";
class App extends React.Component {
state = {
checkboxes: [
{ name: "Check 1", value: false },
{ name: "Check 2", value: false },
{ name: "Check 3", value: false }
]
};
checkboxStateHandler = (event, idx) => {
const { checkbox } = this.state;
checkbox.checkboxes[idx] = event.target.checked;
this.setState({
checkbox
});
};
renderCheckboxes = () => {
return this.state.checkboxes.map((cb, index) => (
<label>
{cb.name}
<input
type="checkbox"
key={index}
checked={cb.value}
onChange={this.checkboxStateHandler}
/>
</label>
));
};
render() {
return <div>{this.renderCheckboxes()}</div>;
}
}
export default App;
Any help will be appreciated. Thank you :)
This will work for you:
import React from "react";
import "./styles.css";
class App extends React.Component {
state = {
checkboxes: [
{ name: "Check 1", value: false },
{ name: "Check 2", value: false },
{ name: "Check 3", value: false }
]
};
checkboxStateHandler = (event, idx) => {
const { checkboxes } = this.state;
checkboxes[idx] = {
...checkboxes[idx],
value: event.target.checked,
}
this.setState({
checkboxes
});
};
renderCheckboxes = () => {
return this.state.checkboxes.map((cb, index) => (
<label>
{cb.name}
<input
type="checkbox"
key={index}
checked={cb.value}
onChange={e => this.checkboxStateHandler(e, index)}
/>
</label>
));
};
render() {
return <div>{this.renderCheckboxes()}</div>;
}
}
export default App;
You must send the event and index to the method in order to change the value, also checkboxStateHandler needs a little changes.
There are few changes needs to be done under map method,
-> Assign key to the immediate parent under map method and in your case it is label
<label key={index}>
....
</label>
-> Then you have to modify the onChange value like,
<input
type="checkbox"
checked={cb.value}
onChange={(e) => this.checkboxStateHandler(e,index)}
/>
Here the event and index needs to passed down as an arguments.
-> Then in checkboxStateHandler function get the parameters and assign the event.target.checked value to checkboxes[idx].value
checkboxStateHandler = (event, idx) => {
const { checkboxes } = this.state;
checkboxes[idx].value = event.target.checked;
this.setState({
checkboxes
});
};
The above code will get rid of all warnings and errors.
Forked codesandbox here..
I am currently facing a problem while i am working on reactJs. I have a reactstrap modal (https://reactstrap.github.io/components/modals/) where i am displaying checkbox items from an array from state. I want display only some of the options like option 1, option 4 and option 6 but not all, how can i hide other options in the view. Here is my code, can anyone help me how can i solve this problem please? And is there a good way to implement this checkbox to check and uncheck in a single or check/uncheck all.Please recommend me a good way like using jquery or anythin related to plain Js.
Help is appreciated. Thank You !
CodeSandBox Code: https://codesandbox.io/s/xj9ppwrq1z
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.min.css';
import { Modal,ModalBody,ModalFooter,ModalHeader,Button,Input,Label } from
"reactstrap";
class CheckBox extends Component{
constructor(props){
super(props);
this.state = {
checkboxModal: false,
checkBoxlists: [
{id:1, name: 'Option 1', isChecked: false},
{id:2, name: 'Option 2', isChecked: false},
{id:3, name: 'Option 3', isChecked: false},
{id:4, name: 'Option 4', isChecked: false},
{id:5, name: 'Option 5', isChecked: false},
{id:6, name: 'Option 6', isChecked: false}
],
};
}
toggleCheckBoxModal = () => {
this.setState({ checkboxModal : !this.state.checkboxModal });
}
// Handles check or uncheck only to a single flag
handleSingleChange = (e) => {
let checkBoxlists = this.state.checkBoxlists;
checkBoxlists.forEach( (item) => {
if(item.name === e.target.name ){
item.isChecked = e.target.checked;
}
});
this.setState({ checkBoxlists : checkBoxlists });
}
//Handle check/uncheck of all flag
handleAllChange = (e) => {
let checkBoxlists = this.state.checkBoxlists;
checkBoxlists.forEach( (item) => {
item.isChecked = e.target.checked;
});
this.setState({ checkBoxlists: checkBoxlists });
}
handleInput = (e) => {
this.setState({ [e.target.name] : e.target.value });
}
render(){
return(
<div>
<Button onClick={this.toggleCheckBoxModal}>Click to Open</Button>
<Modal isOpen={this.state.checkboxModal}>
<ModalHeader toggle={this.checkboxModal}></ModalHeader>
<ModalBody style={{ backgroundColor: "#4e5d6c", color: "#e1ebeb" }}>
<div style={{ margin: "5px 0px 25px 25px"}}><Input type="checkbox" onClick={ this.handleAllChange } value="checkedAll" /> Check/Uncheck All</div>
{this.state.checkBoxlists.map( item => {
return(
<ul key={item.id}>
<li >
<Input
// key={item.id}
type={"checkbox"}
name={item.name}
value={item.name}
checked={item.isChecked}
onChange={this.handleSingleChange}
/>
<Label>{item.name}</Label>
</li>
</ul>
)
})}
</ModalBody>
<ModalFooter>
<Button onClick={this.toggleCheckBoxModal}>Close</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
ReactDOM.render(<CheckBox />, document.getElementById('root'));
The method of the renderCheckboxes() will return checkboxes which you want. I created example array for that. Then use renderCheckboxes() in render()
You can completely remove the handleSinlgeChange() use that in handleAllChange().Like below
import React, { Component } from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import {
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Button,
Input,
Label
} from "reactstrap";
class CheckBox extends Component {
constructor(props) {
super(props);
this.state = {
allChecked:false,
checkboxModal: false,
checkBoxlists: [
{ id: 1, name: "Option 1", isChecked: false },
{ id: 2, name: "Option 2", isChecked: false },
{ id: 3, name: "Option 3", isChecked: false },
{ id: 4, name: "Option 4", isChecked: false },
{ id: 5, name: "Option 5", isChecked: false },
{ id: 6, name: "Option 6", isChecked: false }
]
};
}
toggleCheckBoxModal = () => {
this.setState({ checkboxModal: !this.state.checkboxModal });
};
// Handles check or uncheck only to a single flag
//Handle check/uncheck of all flag
handleAllChange = e => {
let checkBoxlists = this.state.checkBoxlists;
let allChecked = this.state.allChecked;
if (e.target.value === "checkedAll") {
checkBoxlists.forEach(item => {
item.isChecked = e.target.checked;
allChecked = e.target.checked
});
}
else checkBoxlists.find(item => item.name == e.target.name).isChecked = e.target.checked
this.setState({ checkBoxlists,allChecked });
}
handleInput = e => {
this.setState({ [e.target.name]: e.target.value });
};
renderCheckboxes = () => {
let wantedCheckboxes = [1, 4, 6];
return this.state.checkBoxlists.filter(cb => wantedCheckboxes.includes(cb.id))
.map(item => (
<ul key={item.id}>
<li>
<Input
// key={item.id}
type={"checkbox"}
name={item.name}
value={item.name}
checked={item.isChecked}
onChange={this.handleAllChange}
/>
<Label>{item.name}</Label>
</li>
</ul>
))
}
render() {
return (
<div>
<Button onClick={this.toggleCheckBoxModal} style={{ margin: "50px" }}>
Click to Open
</Button>
<Modal isOpen={this.state.checkboxModal}>
<ModalHeader toggle={this.checkboxModal} />
<ModalBody style={{ backgroundColor: "#4e5d6c", color: "#e1ebeb" }}>
<div style={{ margin: "5px 0px 25px 25px" }}>
<Input
type="checkbox"
onClick={this.handleAllChange}
value="checkedAll"
checked={this.state.allChecked}
/>{" "}
Check/Uncheck All
</div>
{this.renderCheckboxes()}
</ModalBody>
<ModalFooter>
<Button onClick={this.toggleCheckBoxModal}>Close</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
ReactDOM.render(<CheckBox />, document.getElementById("root"));
Hope it will help
I would create a function that returns an array of checkBoxLists containing only the items you want displayed at a time
filterOptions = () => {
checkBoxlists.forEach( (item) => {
if(item.id % 2 == 0) // example: only even options
// for 1, 4 6
if(item.id == 1)
newOptions.add(item)
elseif(item.id==4)
newOptions.add(item)
elseif(itemid==6)
newOptions.add(item)
};
return newOptions;
}
It's advice from a newbie but im just trying to help
My problem is that currently the ref returns a validation message for only the last component, when I want it return from both or either one if the input component is empty.
I have tried to add a index and get undefined value or if I dynamically
added it the ref with a unique value 'name'
I read somewhere that the ref need to be unique - but how do I make it unique?
May aim is trigger a validation function from the child component to show an the errors message on form submit.
can anyone suggest how I can do this.
PARENT
class MainForm extends Component {
handleSubmit(e) {
e.preventDefault();
this.inputRef.handleInputChange(e);
}
render() {
const nameFields = [
{
id: 'firstame', type: 'text', name: 'firstname', label: 'First name', required: true,
},
{
id: 'lastName', type: 'text', name: 'lastname', label: 'Last name', required: true,
},
];
return (
<div>
<form onSubmit={e => (this.handleSubmit(e))} noValidate>
<div className="form__field--background">
<p> Please enter your name so we can match any updates with our database.</p>
<div>
{
nameFields.map(element => (
<div key={element.id} className="form__field--wrapper">
<InputField
type={element.type}
id={element.name}
name={element.name}
required={element.required}
placeholder={element.placeholder}
label={element.label}
pattern={element.pattern}
isValid={(e, name, value) => {
this.inputFieldValidation(e, name, this.handleFieldValues(name, value));
}}
ref={c => this.inputRef[`${element.name}`] = c}
/>
</div>
))
}
</div>
</div>
<button type="submit" className="btn btn--red">Update Preferences</button>
</form>
</div>
);
}
}
export default MainForm;
CHILD
class InputField extends Component {
constructor() {
super();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleOnBlur = this.handleOnBlur.bind(this);
this.state = {
valid: null,
message: '',
};
}
/**
* Calls helper function to validate the input field
* Sets the the state for the validation and validation message
*/
validateField(e) {
const props = {
field: e.target,
value: e.target.value,
label: this.props.label,
required: this.props.required,
min: this.props.min,
max: this.props.max,
pattern: this.props.pattern,
emptyError: this.props.emptyFieldErrorText,
invalidError: this.props.invalidErrorText,
};
let validation = this.state;
// helper function will return an updated validation object
validation = fieldValidation(props, validation);
this.setState(validation);
return validation;
}
/**
* Calls validateField method if field is a checkbox.
* Handles the callback isValid state to parent component.
*/
handleInputChange(e) {
if ((e.target.required && e.target.type === 'checkbox')) {
this.validateField(e);
}
}
handleOnBlur(e) {
if (e.target.type !== 'checkbox') {
this.validateField(e);
}
}
render() {
return (
<div >
<label id={`field-label--${this.props.id}`} htmlFor={`field-input--${this.props.id}`}>
{this.props.label}
</label>
{this.props.helpText &&
<p className="form-help-text">{this.props.helpText}</p>
}
<input
type={this.props.type}
id={`field-input--${this.props.id}`}
name={this.props.name && this.props.name}
required={this.props.required && this.props.required}
placeholder={this.props.placeholder && this.props.placeholder}
onBlur={e => this.handleOnBlur(e)}
onChange={e => this.handleInputChange(e)}
ref={this.props.inputRef}
/>
}
{this.state.valid === false &&
<span className="form-error">
{this.state.message}
</span>
}
</div>
);
}
}
export default InputField;
I am using addItem to add a value to a list from another component
I am adding it to this.state.movies. It appears, however it has the inactive/noresults className applied to it.
How do I determine which styling is applied to an item that has not appeared yet (ie using addItem)? Thanks
Full example on Codesandbox is here. Add an movie to the list and you will see it gets the stying applied: https://codesandbox.io/s/3OGK2pP9
Parent component where I add the item
<CreateNew addItem={item => this.setState({ movies: [{ name: item.value.name, genres: item.genres }].concat( movies, ), })} />
Child component that creates the item
class CreateNew extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
genres: '',
};
}
handleSubmit1 = (e, value) => {
e.preventDefault();
this.props.addItem(this.state);
};
onChange = e => {
this.setState({
value: { name: e.target.value },
genres: [{ name: 'Test', type: 1 }, { name: 'Foo', type: 10 }],
});
};
render() {
const { value, genres } = this.props;
return (
<form onSubmit={this.handleSubmit1}>
Add a new movie
<input onChange={this.onChange} value={value} type="text" />
<button type="submit">Add</button>
</form>
);
}
}
Was related to filtering on my const x instead of my state this.state.movies.
I changed it from const filteredResults = andFilter({x}, Object.keys(selectedFilters)); to `const filteredResults = andFilter({this.state.movies}, Object.keys(selectedFilters));
I have a simple form which has a couple of radio buttons that aren't checking. Each button has a change event attached, but still nothing changes. What can I do to not only capture their data, but signify that the input is selected?
The form
FormComponent = React.createClass({
propTypes: {
label: React.PropTypes.string,
onChange: React.PropTypes.func
},
handleEvent(e) {
let {onChange} = this.props;
console.log(e);
},
render() {
const {label} = this.props;
return (
<form className="lm-widget__form lm-flex-row">
<fieldset className="lm-flex-row__column lm-h-flex-50">
<RadioSet group='radio-group'
label={label}
radios={[
{
value: 'new',
checked: true,
changeEvent: this.handleEvent,
text: 'radio one'
},
{
value: 'old',
checked: false,
changeEvent: this.handleEvent,
text: 'radio two'
}
]}
/>
</fieldset>
</form>
)
}
});
The radio buttons
RadioSet = React.createClass({
propTypes: {
group: React.PropTypes.string.isRequired,
label: React.PropTypes.string,
radios: React.PropTypes.arrayOf(
React.PropTypes.shape({
value: React.PropTypes.string.isRequired,
checked: React.PropTypes.bool.isRequired,
changeEvent: React.PropTypes.func.isRequired,
text: React.PropTypes.string.isRequired
})
).isRequired
},
render: function () {
const {group, label, radios} = this.props;
const self = this;
if (label) {
return(
<div className="lm-widget-form__label">
<div className="small">{label}</div>
<div className="segment-controls">
{radios.map(function(radio, i){
return (
<div key={i} className="segment-controls__group-item">
<input type="radio"
name={self.props.group}
className="segment-controls__button"
id={`radio-${i}`}
value={radio.value}
checked={radio.checked}
onChange={radio.changeEvent}
/>
<label htmlFor={`radio-${i}`}
className="segment-controls__label">
<span className="segment-controls__label-text">
{radio.text}
</span>
</label>
</div>
);
})
}
</div>
</div>
)
}
else {
return (
<div className="segment-controls">
{this.props.radios.map(function(radio, i){
return (
<div key={radio.value} className="segment-controls__group-item">
<input type="radio"
name={self.props.group}
className="segment-controls__button"
id={`radio-${i}`}
value={radio.value}
checked={radio.checked}
onChange={radio.changeEvent}
/>
<label htmlFor={`radio-${i}`}
className="segment-controls__label">
<span className="segment-controls__label-text">
{radio.text}
</span>
</label>
</div>
);
})
}
</div>
);
}
}
});
So the issue is that you're telling the first radio button it's checked every time by passing true to it.
If we change your first bit of code to use setState this should work.
FormComponent = React.createClass({
getInitialState() {
return {
checkedIndex: 0
};
},
propTypes: {
label: React.PropTypes.string,
onChange: React.PropTypes.func
},
handleEvent(index, e) {
this.setState({
checkedIndex: index
});
let {onChange} = this.props;
console.log(e);
},
render() {
const {label} = this.props;
const radios = [
{
value: 'new',
checked: false,
changeEvent: this.handleEvent.bind(this, 0),
text: 'radio one'
},
{
value: 'old',
checked: false,
changeEvent: this.handleEvent.bind(this, 1),
text: 'radio two'
}
];
radios[this.state.checkedIndex].checked = true;
return (
<form className="lm-widget__form lm-flex-row">
<fieldset className="lm-flex-row__column lm-h-flex-50">
<RadioSet group='radio-group'
label={label}
radios={radios}
/>
</fieldset>
</form>
)
}
});
Also note we are using bind to maintain the this context of handleEvent and to pass in the proper index.