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

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>

Related

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

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: [] });
}

React: How to get the id's of checked items from the list?

I am displaying the items in a Checkbox list. Items are coming in XML format from Get webapi. This is used for managing the items retire/not retire. Items are displaying with checkboxes and is checked in case of retire. User can retire the item by checking the checkbox, or make the item active by unchecking the checkbox. Please find my get api response and code. Please let me know how to get the list of checked id's. I need to pass comma-delimited id's in Post api.
<?xml version="1.0" encoding="utf-8" ?>
<Category>
<item item-id="1" is-retired="TRUE">Greenhouse</item>. Retired
<item item-id="3" is-retired="TRUE">Instant Issue</item>
<item item-id="13" is-retired="FALSE">My Card</item>. Active
<item item-id="15" is-retired="FALSE">Test_July11</item>
<item item-id="20" is-retired="FALSE">Test_July12</item>
<item item-id="21" is-retired="TRUE">Test_July19</item>
<item item-id="33" is-retired="TRUE">Test_July20</item>
<item item-id="36" is-retired="FALSE">Test_July9</item>
<item item-id="38" is-retired="FALSE">Test88</item>
</Category>
import React from "react";
import axios from 'axios';
import XMLParser from 'react-xml-parser';
export class Delete_Items extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [],
item_id: "",
checkedItems: new Map(),
isChecked: false,
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
if (typeof this.props.key_id !== 'undefined') {
this.getlistofitems();
}
}
componentDidUpdate(prevProps) {
if (prevProps.key_id !== this.props.key_id) {
this.getlistofitems();
}
}
getlistofitems() {
axios
.get(REQUEST_URL, { "Content-Type": "application/xml; charset=utf-8" })
.then(response => {
const jsonDataFromXml = new XMLParser().parseFromString(response.data);
console.log(jsonDataFromXml.getElementsByTagName('item'));
this.setState({ items: jsonDataFromXml.getElementsByTagName('item') })
});
}
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();
const item_id_List = this.state.checkedItem;
const data = {
item_id_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))
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}
<ul style={{ listStyle: 'none' }} >
{
this.state.items.map(item => (
<li key={item.attributes['item-id']} >
<label>
<input type="checkbox" id={item.attributes['item-id']}
defaultChecked={item.attributes['is-retired'] === "TRUE" ? true : false}
value={item.value}
onChange={this.handleChange} /> {item.value}
</label>
</li> ))}
</ul>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
export default Delete_Items;

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>
);
}
}

using checkboxes to change state and sort list

I have a list like this:
<div className="doubleCol">
{this.state.symptoms.map(item => (
<ListItem key={item.ObjectID}>
<input type="checkbox" className="sympSelect" />
{item.name}
</ListItem>
))}
</div>
All the items rendered have checkbox and I want it to filter a different list elsewhere on the page based on which boxes are checked. To do that I need the checkboxes to change the state and pass the new state to a method which is supposed to filter and display only those items on the second list with id's associated to items on the first list.
From what I have read it shouldn't matter for this purpose if the checkboxes are controlled or uncontrolled.
class Home extends React.Component {
state = {
conditions: [],
symptoms: [],
selectedSymptom: []
}
componentDidMount() {
this.getConditionsMethod();
this.getSymptomsMethod();
}
getConditionsMethod = () => {
API.getConditions()
.then(data => {
console.log(data);
data.data.sort((a, b) => a.name.localeCompare(b.name))
this.setState({
conditions: data.data
})
})
.catch(err => console.log(err))
};
filterConditionsMethod = () => {
API.getConditions()
.then(data => {
console.log(data);
data.data.sort((a, b) => a.name.localeCompare(b.name));
this.setState({
selectedSymptom: data.data
})
})
.catch(err => console.log(err))
};
But I am kind of stuck on how to structure the onChange for when the box is checked and how to make that implement the filter.
Here is you solution you can add onChange event for checkbox and filter your records as selectedSymptoms and symptoms. Please check code is
import React, { Component } from "react";
class Home extends Component {
constructor(props) {
super(props);
this.state = {
conditions: [],
symptoms: [
{ ObjectID: 1, name: "xyz" },
{ ObjectID: 2, name: "pqr" }
],
selectedSymptom: [],
checked: ""
};
}
updateCheckBox = (event, item) => {
if (event.target.checked) {
let selectedList = this.state.selectedSymptom;
selectedList.push(item);
this.setState({
...this.state,
checked: this.state.checked == "checked" ? "" : "checked",
selectedSymptom: selectedList
});
} else {
const symptomss = this.state.selectedSymptom.filter(element => {
if (element.ObjectID != data.ObjectID) {
return item;
}
});
this.setState({
...this.state,
checked: "",
selectedSymptom: symptomss
});
}
};
render() {
return (
<div className="doubleCol">
{this.state.symptoms.map(item => (
<ListItem key={item.ObjectID}>
<input
type="checkbox"
className="sympSelect"
onChange={this.updateCheckBox(e, item)}
id="symptoms_id"
defaultChecked={this.state.checked}
/>
{item.name}
</ListItem>
))}
</div>
);
}
}
export default Home;

React - Dynamically add inputs without mutating state

I'm trying to dynamically add inputs when the user clicks the button to add a question.
Usually doing a controlled form is easy as your know what the field names are. But in this situation they are dynamic.
I've got a working solution but it mutates the state.
Is there a better way to do this?
Thanks
JSX
import React, { Component } from 'react';
import axios from 'axios';
import { saveAs } from 'file-saver';
class Form extends Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.handleForm = this.handleForm.bind(this);
this.addQuestion = this.addQuestion.bind(this);
this.removeQuestion = this.removeQuestion.bind(this);
this.state = {
questions: []
}
}
onChange(e, i) {
this.state.questions[i] = e.target.value;
this.setState({
questions: this.state.questions
})
}
handleForm(e) {
e.preventDefault();
const body = {
questions: this.state.questions
};
axios.post('/api/pdfs/create', body)
.then(() => axios.get('/api/pdfs/fetch', { responseType: 'blob' }))
.then((res) => {
const pdfBlob = new Blob([res.data], { type: 'application/pdf' });
return saveAs(pdfBlob, 'questions.pdf');
})
.catch(error => {
console.log(error.response)
});
}
addQuestion() {
this.setState({
questions: [...this.state.questions, '']
});
}
removeQuestion(index) {
this.setState({
questions: this.state.questions.filter((question, i) => i !== index)
});
}
render() {
return (
<div>
<button onClick={this.addQuestion}>Add Question</button>
<form onSubmit={this.handleForm}>
{this.state.questions.map((question, index) => (
<div key={index}>
<input type="text" name={`question-${question}`} onChange={(e) => this.onChange(e, index)} />
<button type="button" onClick={() => this.removeQuestion(index)}>x</button>
</div>
))}
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default Form;
You are mutating the state only in your onChange call, and that can be fixed easily:
onChange(e, i) {
this.setState({
questions: this.state.questions.map((v, i2) => i === i2 ? e.target.value : v),
});
}
(This won't change the functionality though, its just a "best practice improvement")

Categories