React:How to Select All/UnSelect All checkboxes on button click? - javascript

I am displaying data in the checkboxlist. How to implement Select All and UnselectAll buttons that selects all or unselect all checkboxes. Please find my react code and data coming from api.
[ {"templateID":"11","templateName":"All” },
{"templateID":"21","templateName":"SC" }]
import React from "react";
export class Delete_Item extends React.Component {
constructor(props) ;
super(props);
this.state = {
Template_ID: "",
TemplateName: "",
Templatelist: [],
checkedItems: [],
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.getTemplateList();
}
getTemplateList() {
fetch(REQUEST_URL, { credentials: 'include' })
.then(response => response.json())
.then((data) => {
this.setState({
Templatelist: data,
TemplateName: data[0].templateName,
loading: false
})
console.log(this.state.Templatelist);
})
}
handleChange(event) {
const id = parseInt(event.target.id, 10);
const index = this.state.checkedItems.indexOf(id);
const updatedArray = [...this.state.checkedItems];
if (index !== -1) {
updatedArray.splice(index, 1);
} else {
updatedArray.push(id);
}
this.setState((prevState) => ({
checkedItems: updatedArray
}));
console.log(this.state.checkedItems);
}
render() {
return (
<div>
<ul style={{ listStyle: 'none' }} >
{
(this.state.Templatelist.map((item, index) => {
return (
<li key={item.templateID}>
<input type="checkbox" id={item.templateID} value={item.templateName}
onChange={this.handleChange} />
{item.templateName}</li>)}))}</ul>
<input type="button" name="SelectAll" value="Select All" />
<input type="button" name="UnSelectAll" value="Clear All" />
</div>
);
}
}
export default Delete_Item;
thanks

selectAll() {
return this.setState({ checkedItems: this.state.Templatelist.map(id => id) });
}
unselectAll() {
return this.setState({ checkedItems: [] });
}

Related

React: Checkboxlist SelectAll and ClearAll buttons not working

I am displaying data in the checkboxlist. I have implemented Select All and ClearAll buttons that selects all or unselect all checkboxes.
Please find my react code in the sandbox: https://codesandbox.io/s/immutable-pond-07qnue
Please fix my code why SelectAll and ClearAll functionality is not working.
import React from "react";
const data = [
{ templateID: "11", templateName: "All" },
{ templateID: "21", templateName: "SC" }
];
export class Delete_Item extends React.Component {
constructor(props) {
super(props);
this.state = {
Template_ID: "",
TemplateName: "",
Templatelist: [],
checkedItems: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSelectAll = this.handleSelectAll.bind(this);
this.handleClearAll = this.handleClearAll.bind(this);
}
componentDidMount() {
this.getTemplateList();
}
getTemplateList() {
this.setState({
Templatelist: data,
TemplateName: data[0].templateName,
loading: false
});
console.log(this.state.Templatelist);
}
handleChange(event) {
const id = parseInt(event.target.id, 10);
const index = this.state.checkedItems.indexOf(id);
const updatedArray = [...this.state.checkedItems];
if (index !== -1) {
updatedArray.splice(index, 1);
} else {
updatedArray.push(id);
}
this.setState((prevState) => ({
checkedItems: updatedArray
}));
console.log(this.state.checkedItems);
}
handleSelectAll() {
return this.setState({
checkedItems: this.state.Templatelist.map((id) => id)
});
}
handleClearAll() {
return this.setState({ checkedItems: [] });
}
render() {
return (
<div>
<ul style={{ listStyle: "none" }}>
{this.state.Templatelist.map((item, index) => {
return (
<li key={item.templateID}>
<input
type="checkbox"
id={item.templateID}
value={item.templateName}
onChange={this.handleChange}
/>
{item.templateName}
</li>
);
})}
</ul>
<input
type="button"
name="SelectAll"
value="Select All"
onClick={this.handleSelectAll}
/>
<input
type="button"
name="UnSelectAll"
value="Clear All"
onClick={this.handleClearAll}
/>
</div>
);
}
}
export default Delete_Item;
You need to add the checked property to your checkbox based on what you have selected this.state.checkedItems. Also in handleChange method you convert it to an integer and stored while in handleSelectAll method you use the full object. So need to make sure to store at the same type.
import React from "react";
const data = [
{ templateID: "11", templateName: "All" },
{ templateID: "21", templateName: "SC" }
];
export class Delete_Item extends React.Component {
constructor(props) {
super(props);
this.state = {
Template_ID: "",
TemplateName: "",
Templatelist: [],
checkedItems: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSelectAll = this.handleSelectAll.bind(this);
this.handleClearAll = this.handleClearAll.bind(this);
}
componentDidMount() {
this.getTemplateList();
}
getTemplateList() {
this.setState({
Templatelist: data,
TemplateName: data[0].templateName,
loading: false
});
}
handleChange(event) {
const id = event.target.id;
const index = this.state.checkedItems.indexOf(id);
const updatedArray = [...this.state.checkedItems];
if (index !== -1) {
updatedArray.splice(index, 1);
} else {
updatedArray.push(id);
}
this.setState({
checkedItems: updatedArray
});
}
handleSelectAll() {
this.setState({
checkedItems: this.state.Templatelist.map((id) => id.templateID)
});
}
handleClearAll() {
this.setState({ checkedItems: [] });
}
render() {
return (
<div>
<ul style={{ listStyle: "none" }}>
{this.state.Templatelist.map((item, index) => {
return (
<li key={item.templateID}>
<input
type="checkbox"
id={item.templateID}
value={item.templateName}
checked={this.state.checkedItems.some(
(i) => i === item.templateID
)}
onChange={this.handleChange}
/>
{item.templateName}
</li>
);
})}
</ul>
<input
type="button"
name="SelectAll"
value="Select All"
onClick={this.handleSelectAll}
/>
<input
type="button"
name="UnSelectAll"
value="Clear All"
onClick={this.handleClearAll}
/>
</div>
);
}
}
export default Delete_Item;
Sample working at https://codesandbox.io/s/prod-darkness-l2vx52

React, Why selected checkboxes are not checked in case of new selection?

I have list of items that I am showing in Checkboxlist. Items are coming from get webapi and it returns xml. Some of the items are checked on page load. If I make the change in the selection, always only new selection will stay. Why pre-fill selected checkboxes are no more selected in case of change in the selection.
Xml:
<?xml version="1.0"?>
<Product>
<states is-assigned="FALSE" product-state-id="11">Alabama</states>
<states is-assigned="FALSE" product-state-id="12">Alaska</states>
<states is-assigned="FALSE" product-state-id="21">Arizona</states>
<states is-assigned="TRUE" product-state-id="22">Colorado</states> selected on page load
<states is-assigned="TRUE" product-state-id="33">Connect</states> selected on page load
</Product>
</xml>
import React from "react";
import axios from 'axios';
import XMLParser from 'react-xml-parser';
export class AssignStates extends React.Component {
constructor(props) {
super(props);
this.state = {
Template_ID: "",
templatestates: [],
checkedItems: [],
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const id = parseInt(event.target.id, 10);
const index = this.state.checkedItems.indexOf(id);
const updatedArray = [...this.state.checkedItems];
if (index !== -1) {
updatedArray.splice(index, 1);
} else {
updatedArray.push(id);
}
this.setState((prevState) => ({
checkedItems: updatedArray
}));
}
handleSubmit(event) {
event.preventDefault();
const StateID_List = this.state.checkedItems;
const Template_ID = this.props.key_id;
const data = {
Template_ID,
StateID_List
}
fetch(REQUEST_URL, {
method: 'POST',
body: JSON.stringify(data),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success', response));
}
componentDidMount() {
if (typeof this.props.key_id !== 'undefined') {
const Template_ID = this.props.key_id;
if (Template_ID > 0) {
this.getListOfStates(Template_ID);
}
}
}
componentDidUpdate(prevProps) {
const Template_ID = this.props.key_id;
if (prevProps.key_id !== this.props.key_id) {
console.log(`key_id: ${this.props.key_id}`);
this.getListOfStates(Template_ID);
}
}
getListOfStates(Template_ID) {
axios.get(REQUEST_URL, { "Content-Type": "application/xml; charset=utf-8" })
.then(response => {
const jsonDataFromXml = new XMLParser().parseFromString(response.data);
console.log(jsonDataFromXml.getElementsByTagName('states'));
})
.then((data) => {
let items = data.reduce((acc, item) => {
if (item.attributes['is-assigned'] === "TRUE") acc.push(item.attributes['product-state-id']);
return acc;
}, [])
this.setState({
templatestates: data,
checkedItems: items
});
console.log(items);
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<ul style={{ listStyle: 'none' }}>
{(this.state.templatestates.map((item, index) => {
return (
<li key={item.attributes['product-state-id']}>
<input
type="checkbox"
id={item.attributes['product-state-id']}
defaultChecked={item.attributes['is-assigned'] == "TRUE" ? true : false}
value={item.value}
onChange={this.handleChange}
/>
{item.value}
</li>
)
}))}
</ul>
<button type="submit">Submit</button>
<input type="button" name="selectall" value="Select All" />
<input type="button" name="unselectall" value="Clear All" />
</form>
</div>
);
}
}
export default AssignStates;
Thanks
in getListOfStates function i see you are updating the result in prodtemplatestates state. But there is no state named "prodtemplatestates"!!
The checkedItems state should be initialized to the selected XML values when the component mounts.
getListOfStates(Template_ID) {
axios
.get(REQUEST_URL, { "Content-Type": "application/xml; charset=utf-8" })
.then((response) => {
const jsonDataFromXml = new XMLParser().parseFromString(data);
const states = jsonDataFromXml.getElementsByTagName("states");
console.log(states);
this.setState({
templatestates: states,
checkedItems: states
.filter(({ attributes }) => attributes["is-assigned"] === "TRUE")
.map(({ attributes }) => Number(attributes["product-state-id"]))
});
});
}
When mapping the checkbox inputs you should use the checked prop for a controlled input (i.e. checked and onChange props). Use this.state.checkedItems array and check if the current mapped item's id is in the array.
<ul style={{ listStyle: "none" }}>
{this.state.templatestates.map((item, index) => {
return (
<li key={item.attributes["product-state-id"]}>
<label>
<input
type="checkbox"
id={item.attributes["product-state-id"]}
checked={this.state.checkedItems.includes(
Number(item.attributes["product-state-id"])
)}
value={item.value}
onChange={this.handleChange}
/>
{item.value}
</label>
</li>
);
})}
</ul>

How to change the checkbox selection and get the updated id's of checkbox items in form submit in React Component?

I need help in my react code. I am displaying the list of checkbox items using api. My JSON file contains the data which is having IsAssigned True/False. If isAssigned is true for that item, item checkbox will be pre-checked on page load.
Now, I want to change the selection of Checkboxlist items. How can I get the id's of selected Checkboxes and call post/put api calls to make changes in the database.
There are checkboxes that are pre-selected isAssigned=true, unselect the pre-selected checkboxes isAssigned= false, select the checkboxes that are not pre-selected earlier.
Please find my react code and json data below. Also, help me out on achieving the above,
import React from "react";
export class SetDescItems extends React.Component {
static displayName = Assign_TemplateDescriptions.name;
constructor(props) {
super(props);
this.state = {
ProdDescrlist: [],
checkedItems: new Map(),
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
var isChecked = event.target.checked;
var item = event.target.value;
var id = event.target.id;
this.setState(prevState => ({ checkedItems: prevState.checkedItems.set(id, item, isChecked) }));
}
handleSubmit(event) {
event.preventDefault();
//Create an Array.
var checkedItems = new Array();
//Reference all the CheckBoxes
var chks = document.getElementsByTagName("INPUT");
// Loop and push the checked CheckBox id's in Array.
for (var i = 0; i < chks.length; i++) {
if (chks[i].checked) {
checkedItems.push(chks[i].id);
}
}
//Display the selected CheckBox id's.
if (checkedItems.length > 0) {
checkedItems = checkedItems.join(",");
console.log("Selected ids: " + checkedItems);
}
const data = checkedItems;
//write post api here
}
componentDidMount() {
this.getProdDescriptions();
}
async getProdDescriptions () {
const url = “/api/getDescriptions”;
await fetch(url)
.then(response => response.json())
.then((data) => {
this.setState({
ProdDescrlist: data,
loading: false
})
console.log(this.state.ProdDescrlist)
})
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit} >
<ul style={{ listStyle: 'none' }}>
{
(this.state.ProdDescrlist.map((item, index) => {
return (
<li key={index}>
<input type="checkbox"
id={item.ProdDescription_ID}
defaultChecked={item.isAssigned == "TRUE"?true:false}
value={item.DescriptionTextPlain}
onChange={this.handleChange} />
{item.DescriptionTextPlain}
</li>
)
}
))
}
</ul>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default SetDescItems;
[{"ProdDescription_ID":2863,"isAssigned":"TRUE","DisplaySequence":0,"DescriptionTextPlain":"A1Testig"},
{"ProdDescription_ID":2865,"isAssigned":"TRUE","DisplaySequence":0,"DescriptionTextPlain":"test"},
{"ProdDescription_ID":1778,"isAssigned":"FALSE","DisplaySequence":0,"DescriptionTextPlain":"Testing4"},
{"ProdDescription_ID":2864,"isAssigned":"FALSE","DisplaySequence":0,"DescriptionTextPlain":"A2 "},
{"ProdDescription_ID":1544,"isAssigned":"FALSE","DisplaySequence":5,"DescriptionTextPlain":"ProductGuide"},
{"ProdDescription_ID":1535,"isAssigned":"TRUE","DisplaySequence":10,"DescriptionTextPlain":"testexample"},
{"ProdDescription_ID":1536,"isAssigned":"FALSE","DisplaySequence":15,"DescriptionTextPlain":"Note"}]
You need to use checked prop in input tag
import "./styles.css";
import React from "react";
export class SetDescItems extends React.Component {
constructor(props) {
super(props);
this.state = {
ProdDescrlist: [],
checkedItems: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const id = parseInt(event.target.id, 10);
const index = this.state.checkedItems.indexOf(id);
const updatedArray = [...this.state.checkedItems];
if (index !== -1) {
updatedArray.splice(index, 1);
} else {
updatedArray.push(id);
}
this.setState((prevState) => ({
checkedItems: updatedArray
}));
}
handleSubmit(event) {
event.preventDefault();
let value = "";
this.state.checkedItems.forEach((item) => {
if (item) {
value = value === "" ? item : value + "," + item;
}
});
if (value !== "") {
alert(value);
}
}
componentDidMount() {
this.getProdDescriptions();
}
async getProdDescriptions() {
const url = "/api/getDescriptions";
await fetch(url)
.then((response) => response.json())
.then((data) => {
let items = data.reduce((acc, item) => {
if(item.isAssigned === "TRUE") acc.push(item.ProdDescription_ID);
return acc;
}, []);
this.setState({
ProdDescrlist: data,
loading: false,
checkedItems: items
});
});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<ul style={{ listStyle: "none" }}>
{this.state.ProdDescrlist.map((item, index) => {
return (
<li key={index}>
<input
type="checkbox"
id={item.ProdDescription_ID}
defaultChecked={item.isAssigned === "TRUE" ? true : false}
value={item.DescriptionTextPlain}
onChange={this.handleChange}
/>
{item.DescriptionTextPlain}
</li>
);
})}
</ul>
<button type="submit">Submit</button>
</form>
</div>
);
}
}

React and checking condition after passing function through props

I'm fighting with my app since long time and slowly there is progress however I have still problem with one thing
I want to pass function thought props from Form Component to List component, after that I wish to check if button add was clicked if yes then I wish to launch function getMovie() inside List component and send another request to json database. with edit and remove it works as there are in same component, with adding button it is a bit more tricky.
the problem is that if I write just
else if (this.props.addClick) {
this.getMovie();
}
it's keep sending requests to database over and over
below is my code
Form Component
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
type: '',
description: '',
id: '',
movies: [],
errors: "",
}
}
handleSubmit = e => {
e.preventDefault()
const url = `http://localhost:3000/movies/`;
if (this.state.name != "" && this.state.type != "" && this.state.description != "") {
axios
.post(url, {
name: this.state.name,
type: this.state.type,
description: this.state.description,
id: this.state.id,
})
.then(res => {
this.setState({
movies: [this.state.name, this.state.type, this.state.description, this.state.id]
})
})
.then(this.setState({
isButtonRemoveClicked: true
}))
}
else {
this.setState({
errors:"Please, Fill all forms above"
})
}
}
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="Movie" onChange={this.handleChangeOne}/>
<input type="text" placeholder="Type of movie" onChange={this.handleChangeTwo}/>
<textarea placeholder="Description of the movie"
onChange={this.handleChangeThree}></textarea>
<input id="addMovie" type="submit" value="Add movie" ></input>
<p>{this.state.errors}</p>
</form>
<List removeClick={this.handleRemove} editClick={this.editMovie} addClick={this.handleSubmit}/>
</div>
)
List Component
class List extends React.Component {
constructor(props) {
super(props)
this.state = {
movies: [],
isButtonRemoveClicked: false,
}
}
componentDidMount() {
this.getMovie()
}
componentDidUpdate() {
if (this.state.isButtonRemoveClicked === true) {
this.getMovie();
this.timer = setTimeout(() => {
this.setState({
isButtonRemoveClicked: false
})
}, 10)
}
else if (this.props.addClick === true) {
this.getMovie();
}
}
componentWillUnmount() {
clearTimeout(this.timer)
}
getMovie = () => {
const url = `http://localhost:3000/movies`;
axios
.get(url)
.then(res => {
const movies = res.data;
this.setState({
movies: movies,
})
})
.catch((err) => {
console.log(err);
})
}
There is nothing magical ;)
You're start loading data from componentDidUpdate() ... data loads, componentDidUpdate is fired again, again...
Don't handle events this way.
If your main objective is to call function in child component from parent component, then you can use refs.
Example in your code :-
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
type: '',
description: '',
id: '',
movies: [],
errors: "",
}
}
handleSubmit = e => {
e.preventDefault()
const url = `http://localhost:3000/movies/`;
if (this.state.name != "" && this.state.type != "" && this.state.description != "") {
axios
.post(url, {
name: this.state.name,
type: this.state.type,
description: this.state.description,
id: this.state.id,
})
.then(res => {
this.setState({
movies: [this.state.name, this.state.type, this.state.description, this.state.id]
})
})
.then(
this.list.getMovie(); // call child function here
this.setState({
isButtonRemoveClicked: true
}))
}
else {
this.setState({
errors:"Please, Fill all forms above"
})
}
}
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="Movie" onChange={this.handleChangeOne}/>
<input type="text" placeholder="Type of movie" onChange={this.handleChangeTwo}/>
<textarea placeholder="Description of the movie"
onChange={this.handleChangeThree}></textarea>
<input id="addMovie" type="submit" value="Add movie" ></input>
<p>{this.state.errors}</p>
</form>
<List
ref={list => this.list=list } // Create ref here
removeClick={this.handleRemove}
editClick={this.editMovie}
addClick={this.handleSubmit}/>
</div>
)
And in list component no need to use componentDidUpdate getMovie() call.
class List extends React.Component {
constructor(props) {
super(props)
this.state = {
movies: [],
isButtonRemoveClicked: false,
}
}
componentDidMount() {
this.getMovie()
}
getMovie = () => {
const url = `http://localhost:3000/movies`;
axios
.get(url)
.then(res => {
const movies = res.data;
this.setState({
movies: movies,
})
})
.catch((err) => {
console.log(err);
})
}
I think you are handling events in an overcomplicated manner. Why don't you lift props from inside the List component and just trigger the desired behaviour in the Form?. For example:
class List extends React.Component {
handleAddClick() {
this.props.onAddClick()
}
handleEditClick() {
this.props.onEditClick()
}
handleRemoveClick() {
this.props.onRemoveClick()
}
render() {
return (
<div>
<button onClick={() => this.handleAddClick()}>Add</button>
<button onClick={() => this.handleEditClick()}> Edit</button>
<button onClick={() => this.handleRemoveClick()} > Remove</button>
</div>
})
}
and
class Form extends React.Component {
getMovie() {
// Make AXIOS request
}
handleAdd() {
this.getMovie();
}
handleRemove() {
// REMOVE CODE
}
handleEdit() {
// EDIT CODE
}
render() {
<form>
{/* Form elements */}
<List
onAddClick={() => this.handleAdd()}
onRemoveClick={() => this.handleRemove()}
onEditClick={() => this.handleEdit()}
/>
</form>
}
}

React Todo Delete Button Removes all listed items at once

I have 2 files
App.js
import React, { Component } from 'react';
import './App.css';
import ToDo from './components/ToDo.js';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [],
newTodoDescription: ''
};
this.deleteTodo = this.deleteTodo.bind(this);
}
handleChange(e) {
this.setState({ newTodoDescription: e.target.value })
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.newTodoDescription) { return }
const newTodo = { id: this.state.todos.id, description: this.state.newTodoDescription, isCompleted: false };
this.setState({ todos: [...this.state.todos, newTodo], newTodoDescription: '' });
}
toggleComplete(index) {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.isCompleted = todo.isCompleted ? false : true;
this.setState({ todos: todos });
}
deleteTodo(id) {
const remainingToDos = this.state.todos.filter((todo, remainingToDos) => {
if(todo.id !== remainingToDos.id) return todo; });
this.setState({ todos: remainingToDos });
}
render() {
return (
<div className="App">
<h1>Add a ToDo!</h1>
<form onSubmit={ (e) => this.handleSubmit(e)}>
<input type="text"
value={ this.state.newTodoDescription }
onChange={ (e) => this.handleChange(e) }
/>
<input type="submit" value="Add Todo" />
</form>
<ul>
{ this.state.todos.map( (todo) =>
<ToDo key={ todo.id }
description={ todo.description }
isCompleted={ todo.isCompleted }
toggleComplete={ () => this.toggleComplete(todo) }
onDelete={ this.deleteTodo }
/>
)}
</ul>
</div>
);
}
}
export default App;
ToDo.js
import React, { Component } from 'react';
class ToDo extends Component {
render() {
return (
<li>
<input type="checkbox" checked={ this.props.isCompleted } onChange={ this.props.toggleComplete } />
<span>{ this.props.description } {''}</span>
<button onClick={() => this.props.onDelete(this.props.id)}>Remove Todo</button>
</li>
);
}
}
export default ToDo;
What I am trying to accomplish: Add many todos to the list. Click on the remove todo button. ONLY the todo that is selected will be removed.
I am VERY new to react and cannot figure this out. In my deleteToDo method I am trying to filter out the todos and only keep the todos that are current. I am unclear if I am using .filter properly or not.
Problem is that filter() method should return a condition, not value:
deleteTodo(id) {
const remainingToDos = this.state.todos.filter((todo, remainingToDos) => {
return (todo.id !== remainingToDos.id)
});
this.setState({ todos: remainingToDos });
}
I am fairly sure you have simply over-complicated your code. You are not using the parameter id that you have passed into your method at all. Your deleteTodo method could simply be:
deleteTodo = (id) => {
var remainingToDos = this.state.todos.filter((todo) => {
return todo.id === id
});
this.setState({ todos: remainingToDos })
}

Categories