Handle select all checkboxes - ReactJS - javascript

Hey guys i am trying to assign a fucntion on my chechbox select all button to flip the state when button is clicked but i am doing something wrong . Can somebody help me ?
My state :
constructor(props) {
super(props);
this.state = {
allCheckboxes: false
};
handleAllCheckboxes = (e) => {
const allCheckboxesChecked = e.target.checked
let checkboxes = document.getElementsByName('checkbox')
this.setState({
allCheckboxes: allCheckboxesChecked
})
console.log(allCheckboxesChecked)
My single checkbox :
<Checkbox
checked={this.handleAllCheckboxes ? true : false}
name='checkbox'
color='default'
value={JSON.stringify({ documentId: rowData.documentId, documentNumber: rowData.documentNumber })}
onClick={this.handleCheckboxClick}
/>
My select all checkbox:
<Checkbox
onChange={this.handleAllCheckboxes}
indeterminate
/>Select All
The problem is that no matter what i do the state stay the same . It doesnt flip to true or false .
UPDATE
UPDATE
https://codesandbox.io/s/upbeat-khorana-j8mr6

Hi Your Checkbox handler should lie out of constructor.
like below:
constructor(props) {
super(props);
this.state = {
allCheckboxes: true
};
}
handleAllCheckboxes = (e) => {
const allCheckboxesChecked = e.target.checked
let checkboxes = document.getElementsByName('checkbox')
this.setState({
allCheckboxes: allCheckboxesChecked
})
console.log(allCheckboxesChecked)
}
and you have written checked={this.handleAllCheckboxes ? true : false} which looks wrong.Because **this.handleAllCheckboxes is already defined and therefore it will always return true.( Because function is always available.) **. Secondly handleAllCheckboxes is also not returning any true/false.

You need to keep your checkboxes state in state, when clicking select all change their state to true and vise versa.
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
this.state = {
checkBoxes: {
vehicle1: false,
vehicle2: false,
vehicle3: false,
}
};
}
handleCheckBoxes = (checkBox, checkAll = false) => {
if (checkAll) {
const checkBoxes = { ...this.state.checkBoxes };
Object.keys(checkBoxes).forEach((key) => {
checkBoxes[key] = checkBox.target.checked;
});
this.setState({
checkBoxes: checkBoxes
})
return;
}
const { checked, name } = checkBox.target;
this.setState(
prevState => {
return {
checkBoxes: { ...prevState.checkBoxes, [name]: checked }
};
},
() => console.log(this.state)
);
// console.log(checkBox.target.checked);
};
render() {
return (
<div>
<label>
<input
type="checkbox"
onChange={e => this.handleCheckBoxes(e, true)}
name="vehicle1"
value="Bike"
/>
Select All
</label>
<br />
<input
type="checkbox"
onChange={this.handleCheckBoxes}
name="vehicle1"
value="Bike"
checked={this.state.checkBoxes["vehicle1"]}
/>
<input
type="checkbox"
onChange={this.handleCheckBoxes}
name="vehicle2"
value="Car"
checked={this.state.checkBoxes["vehicle2"]}
/>
<input
type="checkbox"
onChange={this.handleCheckBoxes}
name="vehicle3"
value="Boat"
checked={this.state.checkBoxes["vehicle3"]}
/>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
</script>

There is a package grouped-checkboxes which can solve this problem.
You can simply wrap the checkboxes in a CheckboxGroup and add an AllChecker.
import React from 'react';
import {
CheckboxGroup,
AllCheckerCheckbox,
Checkbox
} from "#createnl/grouped-checkboxes";
const App = (props) => {
const { products } = props
return (
<CheckboxGroup onChange={console.log}>
<label>
<AllCheckerCheckbox />
Select all
</label>
{options.map(option => (
<label>
<Checkbox id={option.id} />
{option.label}
</label>
))}
</CheckboxGroup>
)
}
More examples see https://codesandbox.io/s/grouped-checkboxes-v5sww

Related

setState for clicked item only in react app

In my react app i have multiple checkboxes and I'm toggling the checked state using onClick, it's setting the state but it's changing it for all the checkboxes in the page, i want only the pressed one, here is the code:
Initial state:
state: {checked: false}
Checkbox:
return boxes.map(box => (
<Checkbox checked={this.state.checked} onClick={() => this.onCheck(box.id)} />
))
Function:
onCheck(id) { this.setState({ checked: !this.state.checked }); }
Then you'll have to have one state variable for each checkbox. For simplicity, let's put all booleans defining whether the n-th checkbox has been checked into a single array.
You can write a minimal component like this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { boxes: [{id: 10}, {id: 20}] };
this.state.checked = this.state.boxes.map(() => false);
this.onCheck = this.onCheck.bind(this);
}
onCheck(id) {
let index = this.state.boxes.findIndex(box => box.id==id);
this.setState({
checked: this.state.checked.map((c,i) => i==index ? !c : c)
})
}
render() {
return (<div>
{this.state.boxes.map((box,i) => (
<input
key={box.id}
type="checkbox"
checked={this.state.checked[i]}
onChange={() => this.onCheck(box.id)}
/>
))}
<pre>this.state = {JSON.stringify(this.state,null,2)}</pre>
</div>);
}
}
ReactDOM.render(<App/>, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
It's changing all of the checkboxes because all of the checkboxes are referring to the same variable in state. You could store their ids in an array:
state: {
checkedIdArray: []
}
Then check if the current box's id is in the array to determine whether it is checked:
<Checkbox
key={box.id}
checked={this.state.checkedIdArray.includes[box.id]}
onClick={() => this.onCheck(box.id)}
/>
Finally, your onCheck() method would look something like this:
onCheck(id) {
if (this.state.checkedIdArray.includes(id)) {
this.setState({
checkedIdArray: this.state.checkedIdArray.filter((val) => val !== id)
});
} else {
this.setState({
checkedIdArray: [...this.state.checkedIdArray, id]
});
}
}
Haven't tested or anything but something like this should get you where you want to go.

React - render certain div based on react-select selectedOption

I'm using react-select to render two types of "job" options. From the dropdown the user is able to select either of the options. Based on the option selected they should render different divs that contain more input values. The input values are dependent on the selectedOption. I have two class components with render methods that should display the different inputs corresponding to the jobType
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedOption: null
};
this.onChange = this.onChange.bind(this);
this.handleChange = this.handleChange.bind(this);
}
onChange = e => {
this.set({ [e.target.name]: e.target.value });
console.log([e.target.value]);
};
handleChange = selectedOption => {
this.setState({ selectedOption });
console.log("Option selected: ", selectedOption);
};
render() {
const { selectedOption } = this.state;
return (
<div>
<fieldset>
<legend>Parameters</legend>
<label htmlFor="jobType" style={{ display: "block" }}>
jobType:
</label>
<div>
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
placeholder="Select a jobType..."
isSearchable={options}
/>
</div>
</fieldset>
<div>
{selectedOption === "Batch" ? (
<BatchParams />
) : selectedOption === "Streaming" ? (
<StreamingParams />
) : null}
</div>
</div>
);
}
}
So let's say when the Streaming option is selected from the dropdown the following class component should be rendered:
class StreamingParams extends React.Component {
constructor(props) {
super(props);
this.state = {
maxHits: 1
};
this.handleMaxHitsChange = this.handleMaxHitsChange.bind(this);
}
handleMaxHitsChange = e => {
this.set({ [e.target.name]: e.target.valu });
};
render() {
return (
<div>
<label>maxHits:</label>
<input
type="number"
name="maxHits"
onChange={this.handleMaxHitsChange}
placeholder="1"
min="1"
step="1"
required
/>
</div>
);
}
}
I can't quite get the additional input boxes to render, not sure if I'm taking the correct approach here. I have included a codesandbox with my issue.
So it looks like the value that is getting set in this.state.selectedOption is an object with a value and a label field.
So you need to key off of those. Instead of doing this
{selectedOption === "Batch" ? (
<BatchParams />
) : selectedOption === "Streaming" ? (
<StreamingParams />
) : null}
Do this
{selectedOption && selectedOption.value === "batch" ? (
<BatchParams />
) : selectedOption && selectedOption.value === "streaming" ? (
<StreamingParams />
You should opt for value instead of label in case of localization or translations.
Fork
https://codesandbox.io/s/ll5p30nx5q
Only the ternary operator has to be changed: find an updated codesandbox here.
In the ternary operators you will have to check this.state.selectedOption.value as that is where your option value is stored.
{!this.state.selectedOption ?
null :
this.state.selectedOption.value === "batch" ? (
<BatchParams />
) : (
<StreamingParams />
)
}
Also you will have to first check for null as that is the initial value you get for this.state.selectedOption when no element in the select has been set.
The issue was that you have to take the value in the selectedOptions and assign that value to the selectedOption in the event handler setState. You were trying to assign an object and therefore the issue. Have made the changes in the sandbox also. Hope it helps.
import React from "react";
import ReactDOM from "react-dom";
import Select from "react-select";
import "./styles.css";
const options = [
{ value: "batch", label: "Batch" },
{ value: "streaming", label: "Streaming" }
];
class BatchParams extends React.Component {
constructor(props) {
super(props);
this.state = {
batchNumber: 1
};
this.handleBatchNumChange = this.handleBatchNumChange.bind(this);
}
handleBatchNumChange = e => {
this.set({ [e.target.name]: e.target.valu });
};
render() {
return (
<div>
<label>batchNumberSize:</label>
<input
type="number"
name="batchNumberSize"
onChange={this.handleBatchNumChange}
placeholder="1"
min="1"
step="1"
required
/>
</div>
);
}
}
class StreamingParams extends React.Component {
constructor(props) {
super(props);
this.state = {
maxHits: 1
};
this.handleMaxHitsChange = this.handleMaxHitsChange.bind(this);
}
handleMaxHitsChange = e => {
this.set({ [e.target.name]: e.target.valu });
};
render() {
return (
<div>
<label>maxHits:</label>
<input
type="number"
name="maxHits"
onChange={this.handleMaxHitsChange}
placeholder="1"
min="1"
step="1"
required
/>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedOption: null
};
this.onChange = this.onChange.bind(this);
this.handleChange = this.handleChange.bind(this);
}
onChange = e => {
this.set({ [e.target.name]: e.target.value });
console.log([e.target.value]);
};
handleChange =( {value}) => {
console.log(value);
this.setState({ selectedOption: value });
};
render() {
const { selectedOption } = this.state;
return (
<div>
<fieldset>
<legend>Parameters</legend>
<label htmlFor="querySchemaName" style={{ display: "block" }}>
jobType:
</label>
<div>
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
placeholder="Select a jobType..."
isSearchable={options}
/>
</div>
</fieldset>
<div>
{selectedOption === "batch" && <BatchParams /> }
{selectedOption === "streaming" && <StreamingParams />}
</div>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

ReactJS - Checkbox onChange event not firing

I'm trying to implement a fields set of checkboxes in React rendered from an object as follows:
constructor() {
this.state.todo = {
eat: true,
sleep: false,
react: true
}
this.toggleCheckbox = this.toggleCheckbox.bind(this);
}
toggleCheckbox(e){
console.log(e); // nothing :-/
}
render() {
return (
<div>
{ Object.keys(this.state.todo).map((val, i) => (
<div key={i} >
<input
type="checkbox"
value={val}
onChange={this.toggleCheckbox}
checked={this.state.todo[val]}
/><label>{val}</label>
</div>
))}
</div>
)
}
Everything renders correctly but I am not able change any of the checkboxes. console logging the toggleCheck() event is not being triggered.
Ive tried using onClick vs onChange which has no effect.
You are getting the keys from this.state.tables, but your state is called this.state.todo.
You can use each value as name instead and toggle the relevant todo state property with that.
Example
class App extends React.Component {
state = {
todo: {
eat: true,
sleep: false,
react: true
}
};
toggleCheckbox = e => {
const { name } = e.target;
this.setState(prevState => ({
todo: {
...prevState.todo,
[name]: !prevState.todo[name]
}
}));
};
render() {
return (
<div>
{Object.keys(this.state.todo).map((val, i) => (
<div key={i}>
<input
type="checkbox"
name={val}
onChange={this.toggleCheckbox}
checked={this.state.todo[val]}
/>
<label>{val}</label>
</div>
))}
</div>
);
}
}
ReactDOM.render(<App />, 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>

Printing list in <ul>

I want to print a new <ul> list of <li> movies.
I don't see any list nor elements.
I also get a warning:
index.js:2178 Warning: A component is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/docs/forms.html#controlled-components
in input (at index.js:54)
in label (at index.js:52)
in form (at index.js:51)
in div (at index.js:50)
in Movie (at index.js:70)
This is my code:
class Movie extends React.Component {
constructor(props) {
super(props);
this.state = {value: '',
list: [],
checked: true
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.addMovie = this.addMovie.bind(this);
this.listMovies = this.listMovies.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
event.preventDefault();
this.addMovie();
}
addMovie(value){
this.setState({ list: [...this.state.list, value] });
console.log(...this.state.list);
}
listMovies(){
return(
<ul>
{this.state.list.map((item) => <li key={this.state.value}>{this.state.value}</li>)}
</ul>
);
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Movie name:
<input name="movieName" type="text" value={this.state.movieName} onChange={this.handleChange} />
Favorite?
<input name="favorite" type="checkbox" checked={this.state.favorite} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
<button onClick={this.listMovies}>
List Movies
</button>
</div>
);
}
}
ReactDOM.render(
<Movie />,
document.getElementById('root')
);
I would really want to print only my Favorites movies
I'm guessing you want a simple movies list with favorites. Not the best one but working code:
import React from 'react';
import { render } from 'react-dom';
class App extends React.Component {
state = {
favorite: false,
movieName: "",
movies: [],
filter: true,
};
handleChange = (event) =>
event.target.name === "favorite"
? this.setState({ [event.target.name]: event.target.checked })
: this.setState( { [ event.target.name]: event.target.value } );
handleSubmit = ( event ) => {
event.preventDefault();
this.setState({
movies: [...this.state.movies, {name: this.state.movieName, favorite: this.state.favorite }]
});
}
listFavoriteMovies = () => (
<ul>
{this.state.movies
.filter( movie => movie.favorite )
.map( movie => <li>{movie.name}</li>)}
</ul>
);
listAllMovies = () => (
<ul>
{this.state.movies
.map(movie => <li>{movie.name}</li>)}
</ul>
);
changeFilter = () =>
this.setState( prevState => ( {
filter: !prevState.filter,
}))
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Movie name:
<input name="movieName" type="text" onChange={this.handleChange} />
Favorite?
<input name="favorite" type="checkbox" onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
<p>Showing only favorite movies.</p>
<ul>
{
this.state.filter
? this.listFavoriteMovies()
: this.listAllMovies()
}
</ul>
<button onClick={this.changeFilter}>Click toggle for all/favorites.</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
if you initially pass undefined or null as the value prop, the
component starts life as an "uncontrolled" component. Once you
interact with the component, we set a value and react changes it to a
"controlled" component, and issues the warning.
In your code initialise movieName in your state to get rid of warning.
For more information check here

React input checkbox select all component

I'm trying to build a proper react input checkbox select all component. The idea is that there is a component <InputCheckboxAll> and <InputCheckbox> and I'd be able to check the <InputCheckboxAll> and all of the <InputCheckbox> would be selected as well.
I'm having two issues.
If <InputCheckboxAll> is checked I can't unselect any of the <InputCheckbox>.
If all of the <InputCheckbox> are checked then <InputCheckboxAll> should be checked.
Here's the example.
var InputCheckboxAll = React.createClass({
handleChange: function (event) {
this.props.handleChange(event)
},
render: function () {
return (
<input
type='checkbox'
{...this.props}
onChange={this.handleChange} />
)
}
})
var InputCheckbox = React.createClass({
getInitialState: function () {
return {
checked: this.props.checked
}
},
render: function () {
var checkedValue = this.props.allChecked ? true : this.state.checked
return (
<input
checked={checkedValue}
type='checkbox'
{...this.props}/>
)
}
})
var Test = React.createClass({
getInitialState: function () { return {allChecked: false}; },
handleChange: function (event) {
var $elm = $(event.target)
var checked = $elm.prop('checked')
this.setState({
allChecked: checked
})
},
render: function () {
return (
<div>
Select All: <InputCheckboxAll handleChange={this.handleChange}/><br/>
<InputCheckbox allChecked={this.state.allChecked}/><br/>
<InputCheckbox allChecked={this.state.allChecked}/><br/>
<InputCheckbox allChecked={this.state.allChecked}/><br/>
</div>
)
}
})
React.render(<Test/>, document.body)
I think there could be some modifications to your implementation to achieve the desired results in a more React'esque form.
What you should get rid of first, is the InputCheckboxAll checkbox class, and the allChecked prop of the InputCheckbox class. A checkbox is a relatively dumb element, it should not know about concepts such as Everything is selected.
Instead, the checkbox should be implemented as an item that is simply either checked or unchecked.
var InputCheckbox = React.createClass({
getDefaultProps: function () {
return {
checked: false
}
},
render: function () {
return (
<input
checked={this.props.checked}
type='checkbox'
{...this.props}/>
)
}
})
The state of your app (concepts such as All Selected) should be managed from the main App, keeping lower level elements stateless. The state of the main app can simply represent the checked status of each of your checkboxes:
getInitialState: function () {
return {
// 3 checkboxes, all initialized as unchecked
checked: [false, false, false]
};
},
Now, you can recreate the render function to draw 3 checkboxes, plus your select all checkbox. Each <InputCheckbox> can be binded to its own data in the this.state.checked array. When the <Inputcheckbox> changes, we bind an index to the change handler, so we know which array element to modify.
render: function () {
// Recalculate if everything is checked each render, instead of storing it
var isAllChecked = this.state.checked.filter(function(c) {
return c;
}).length === this.state.checked.length;
return (
<div>
Select All: <InputCheckbox
onChange={this.selectAll}
checked={isAllChecked}/><br/>
<InputCheckbox
checked={this.state.checked[0]}
onChange={this.handleChange.bind(this, 0)}/><br/>
<InputCheckbox
checked={this.state.checked[1]}
onChange={this.handleChange.bind(this, 1)}/><br/>
<InputCheckbox
checked={this.state.checked[2]}
onChange={this.handleChange.bind(this, 2)}/><br/>
</div>
)
}
You don't need to store any state related to All Selected. Instead, it would be better to recalculate if everything is selected or not during every render. When the Select All checkbox is checked, we simply set every element of this.state.checked to true.
This also has the advantage of when you manually select all the checkboxes, the select all checkbox will check itself.
Here's a sample implementation:
https://jsfiddle.net/rsupvxry/
I came across to this thread very late. Below solution works for me with below structure.
There are 3 components which makes this feature clean and reusable.
CheckBox - Reusable Component
CheckBoxList - Reusable Component
CityList - End level where you can create states list or any list by cloning this.
Stack Blitz with Module - https://stackblitz.com/edit/react-check-box-list
Standlone Code is below
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>React: Select All or DeSelect All</title>
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script type="text/babel">
function CheckBox({name, value, tick, onCheck}) {
return (
<label>
<input
name={name}
type="checkbox"
value={value}
checked={tick || false}
onChange={onCheck}
/>
{value}
</label>
);
}
function CheckBoxList ({options, isCheckedAll, onCheck}) {
const checkBoxOptions = (
<div className="checkbox-list">
{options.map((option, index) => {
return (
<CheckBox key={index} name={option.name} value={option.value} tick={option.checked} onCheck={(e) => onCheck(option.value, e.target.checked)} />
);
})}
</div>
);
return (
<div className="checkbox-list">
<CheckBox name="select-all" value="ALL" tick={isCheckedAll} onCheck={(e) => onCheck('all', e.target.checked)} />
{checkBoxOptions}
</div>
);
}
class CityList extends React.Component {
constructor(props) {
super(props);
this.state = {
isAllSelected: false,
checkList: [
{
name: "city",
value: "bangalore",
checked: false,
},
{
name: "city",
value: "chennai",
checked: false,
},
{
name: "city",
value: "delhi",
checked: false,
}
]
};
}
onCheckBoxChange(checkName, isChecked) {
let isAllChecked = (checkName === 'all' && isChecked);
let isAllUnChecked = (checkName === 'all' && !isChecked);
const checked = isChecked;
const checkList = this.state.checkList.map((city, index) => {
if(isAllChecked || city.value === checkName) {
return Object.assign({}, city, {
checked,
});
} else if (isAllUnChecked) {
return Object.assign({}, city, {
checked: false,
});
}
return city;
});
let isAllSelected = (checkList.findIndex((item) => item.checked === false) === -1) || isAllChecked;
this.setState({
checkList,
isAllSelected,
});
}
render() {
return (<CheckBoxList options={this.state.checkList} isCheckedAll={this.state.isAllSelected} onCheck={this.onCheckBoxChange.bind(this)} />);
}
}
ReactDOM.render(
<CityList />,
document.getElementById('root')
);
</script>
</head>
<body>
<div id="root"></div>
</body>
</html>
There is a simple package that solves this problem grouped-checkboxes.
In your case the render function will look like this:
render: function () {
return (
<CheckboxGroup>
Select All: <AllCheckerCheckbox /><br/>
<Checkbox id="option-0" onChange={this.handleChange.bind(this, 0)}/><br/>
<Checkbox id="option-1" onChange={this.handleChange.bind(this, 1)}/><br/>
<Checkbox id="option-2" onChange={this.handleChange.bind(this, 2)}/><br/>
</CheckboxGroup>
)
}
More examples see Codesandbox example
I made the check all option how below:
JS code:
const checkAll = (e) => {
var value = false
if(e.target.checked){
value = true;
}
Array.from(document.querySelectorAll("input[name="+name+"]"))
.forEach((checkbox) => {
document.getElementById(checkbox.id).checked = value;
});
}
HTML code (Check All):
<input type="checkbox" name="all" onChange={checkAll} />
HTML code (Options):
<input type="checkbox" name={name} id={name+index} value={obj.id} />
The options was created using the loop where the id is unique for such checkbox.

Categories