How to remove unchecked items from cart state in React - javascript

I have items displayed with check boxes and once clicked/checked they are added to the cart. When unchecked they are added to the cart again. I am not sure how to toggle the checked to remove the item when unchecked.
export class DestinationPrices extends React.Component {
constructor(props) {
super(props);
this.state = {
flightData: [],
isChecked: props.isChecked || false,
data: "",
cart: []
};
this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
}
// ...
}
Select(FD) {
return (
<div>
{FD.FlightID}
<label>
<Checkbox
id={FD.FlightID}
name={FD.FlightID}
value={this.state.isChecked}
onChange={() => this.handleCheckboxChange(FD)}
/>
<span>Select</span>
</label>
</div>
);
}
handleCheckboxChange = id => {
const cartItem = this.state.cart.filter(x => x.FlightID === id.FlightID);
this.setState({
isChecked: !this.state.isChecked,
cart: [...this.state.cart, id]
});
}
When the item is checked, it displays in the cart with some details.
With every click of the checkbox, the item adds to state and shows in the card, regardless if it is checked or unchecked. I need to delete the item from state if the item is unchecked.
Do I check if the item is already there and delete from cart?
render() {
var data = this.props.cart;
var arry = [];
arry.push(data);
return (
<div>
<Card body>
<CardTitle>
<h3>
<b>Flights Selected : </b>
</h3>
</CardTitle>
<CardText>
<span className="fa fa-cart-plus fa-2x"> {data.length} </span>{" "}
{this.getData()}
</CardText>
<div />
</Card>
</div>
);
}
Any help would be greatly appreciated, thanks!

One way of going about it is to do how you outlined in your question: check if the item already is in the cart. If it is, you can remove it from the cart. It it's not, you can add it to the cart.
handleCheckboxChange = item => {
this.setState(prevState => {
const isItemInCart = prevState.cart.some(el => el.FlightID === item.FlightID);
const cart = isItemInCart
? prevState.cart.filter(el => el.FlightID !== item.FlightID)
: [...prevState.cart, item];
return { cart };
});
}

Related

React changing the state when the button is clicked

I am creating a react app where I want to output possible diseases if the symptoms button is clicked.
state = {
user_symptoms = [],
user_possible_disease = []
}
Disease = {
'aids': ['fever', 'cough', 'dysentery'],
'corona': ['fever', 'cough', 'breathe_problem'],
'heart_attack': ['angina', 'pain', 'head_ache'],
[A bunch of objects like this]
}
render() {
return(
<div>
<p>{{this.state.user_possible_disease.map((key, index) => {
return <h2 key={index}>{Object.keys(key)}</h2>
})}}</p>
<button value='cough' className='unclicked' />
<button value='angina' className='unclicked' />
<button value='pain' className='unclicked' />
<button value='breathe_problem' className='unclicked' />
</div>
)
}
So if I click any button of the symptoms, then the possible disease object with any of those symptoms will be added in the user_possible_dissease
Suppose I have clicked on the cough button so the user_possible_disease: [{'aids': ['fever', 'cough', 'dysentery'],
'corona': ['fever', 'cough', 'breathe_problem'],}] will be like this and if I unclick the button the possible diseases will be gone from the state.
I guess you wanted to show diseases for given symptoms. You can do the following:
class App extends React.Component {
state = {
user_symptoms: [],
user_possible_disease: [],
};
Disease = {
aids: ['fever', 'cough', 'dysentery'],
corona: ['fever', 'cough', 'breathe_problem'],
heart_attack: ['angina', 'pain', 'head_ache'],
};
toggleSymptom = (e) => {
let user_symptoms = this.state.user_symptoms;
if (user_symptoms.includes(e.target.value)) {
//we already have this symptom then remove it
user_symptoms = user_symptoms.filter(
(s) => s !== e.target.value
);
} else {
//we dont have the symptom so add it
user_symptoms = [...user_symptoms, e.target.value];
}
this.setState({
user_symptoms,
user_possible_disease: user_symptoms.length //do we have symptoms
? Object.entries(this.Disease) //look for deseases
.filter(([, diseaseSymptom]) =>
user_symptoms.every((
s //all symptoms are symptoms of disease
) => diseaseSymptom.includes(s))
)
.map(([key]) => key) //only need key of the object
: [],
});
};
render() {
return (
<div>
<ul>
{this.state.user_possible_disease.map((d) => (
<li key={d}>{d}</li>
))}
</ul>
<button
value="cough"
className="unclicked"
onClick={this.toggleSymptom}
>
cough
</button>
<button
value="angina"
className="unclicked"
onClick={this.toggleSymptom}
>
angina
</button>
<button
value="pain"
className="unclicked"
onClick={this.toggleSymptom}
>
pain
</button>
<button
value="breathe_problem"
className="unclicked"
onClick={this.toggleSymptom}
>
breathe problem
</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
First, I'd recommend storing the selected diseases in a JSON, instead of array.
state = {
user_possible_disease = {}
}
Then define the onButtonClick function:
onButtonClick (e) {
const disease = e.target.value;
const isActive = this.state.user_possible_disease[disease];
if (isActive) {
// Remove this disease from state;
const { [disease]: _, ...restDiseases } = this.state.user_possible_disease;
this.setState(restDiseases);
} else {
// Add this disease to state;
this.setState({
...this.state.user_possible_disease,
[disease]: Disease[disease]
})
}
}
And at last attach the onButtonClick function to each button:
<button
value='cough'
onClick={this.onButtonClick}
className={this.state.user_possible_disease['cough'] ? 'clicked' : 'unclicked'} />
Also one tip: Try not to duplicate any code/values. For example in the moment user clicks the button, we store the very same array of symptoms into the state. And that array exists both in the Disease constant AND in the state.
A better practice would be just to store the selected disease keys in thee state, like: ['aids', 'corona'], and then when user submits the form, to generate they request payload, by looping the selected diseases (from state), find their related symptoms and push them to they payload.
This way you lift off the component's state, e.g. it holds less data.
Add an onClick event to the button(s) and then set the right diseases based on the value of the clicked button.
const Disease = {
corona: ["fever", "cough", "breathe_problem"]
};
class App extends React.Component {
state = {
user_possible_disease: []
};
// This function will be called for all buttons
setPossibleDiseases = (event) => {
// The Disease[event.target.value] fetches the diseases from the Diseases object
this.setState({
user_possible_disease: Disease[event.target.value]
});
};
render() {
return (
<div>
<div>
{this.state.user_possible_disease.map((disease, index) => {
return <h2 key={index}>{disease}</h2>;
})}
</div>
<button
value="corona"
className="unclicked"
onClick={this.setPossibleDiseases}
>
Corona
</button>
</div>
);
}
}
In your example you have a { to much in {{this.state.user_poss.... and also an h2 cannot/should not be inside a p.

how to add or remove tables dynamically in ReactJS

i want to add a table row by clicking Add, and remove a table row by clicking the small red div inside the table, while retaining the color change option when table is clicked on.
I've been trying for hours, but i'm still new to ReactJS, maybe someone could give me a hint, how to do this, for example with help of an array, a boolean or a for loop? I can't get the right way yet, would be thankful for your input.
i've been thinking about this kind of logic, but haven't been able to implement it yet..
{Boolean(this.state.rows.length) && (
<div onClick={this.handleRemoveRow}></div>
)}
https://jsfiddle.net/mattighof/0uop13kd/
Do the following:
Maintain a state say list and store all your items
Create onClick handlers for adding and removing items in the table
update the state when you add/remove
iterate and render this.state.list
Make sure to do event.stopPropagation() in the remove handler. this way your colour change functionality still works.
See here the implementation of adding and removing item
Code Snippet:
class Table extends React.Component {
constructor(props) {
super(props);
this.state = {
tableColor: true,
list: []
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
tableColor: !this.state.tableColor
});
}
addItem() {
this.setState({ list: this.state.list.concat("item") });
}
removeItem(e, index) {
e.stopPropagation();
this.setState({ list: this.state.list.filter((_, i) => index !== i) });
}
render() {
return (
<div className="container">
<button onClick={this.addItem} type="button">
Add
</button>
<table>
{this.state.list.map((item, index) => {
return (
<tr>
<td
className={this.state.tableColor ? "trRed" : "trBlack"}
onClick={this.handleClick}
>
{item}
<div
onClick={e => this.removeItem(e, index)}
className="innerDiv"
/>
</td>
</tr>
);
})}
</table>
</div>
);
}
}
This is one of the ways you can do it:
class Table extends React.Component {
constructor(props){
super(props)
this.state ={
rows:[{id:8,name:'item8',tablecColor:'trBlack'}],
tableColor: true
}
this.handleClick = this.handleClick.bind(this);
this.handleAdd = this.handleAdd.bind(this);
this.renderRows = this.renderRows.bind(this);
}
handleClick(clickedRow){
const {rows} = this.state;
let newRows = rows.map(row => {
if(row.id === clickedRow.id) {
row.tableColor = 'trRed'
return row
}
return row;})
this.setState({rows:newRows})
}
handleAdd() {
const {rows} = this.state;
const count = rows.length;
rows.push({id:count,name:count,tablecColor:'trBlack'})
this.setState({rows:rows})
}
renderRows() {
return this.state.rows.map(row => {
return (<tr>
<td className={row.tableColor}>
<div>{row.name}
<div onClick={() => this.handleClick(row)}
className="innerDiv">
</div>
</div>
</td>
</tr>)
});
}
render(){
return (
<div className="container">
<button type="button">Add</button>
<table>
{this.renderRows()}
</table>
</div>
)
}
}
ReactDOM.render(<Table />, document.querySelector("#app"));

Push dynamically added html list item into last array

How can i push html into the last array. I was trying to add an item and supposed be add instantly into list array. The cod is working except I'm struggling to add new list into last array.
function addItem(id,name){
const array = JSON.parse(localStorage.getItem('categories'));
array.push({
name: name,
id:id,
});
//<li>{name}</li> push this into last array
localStorage.setItem('categories',JSON.stringify(array));
}
{categories.map(function(item, key){
return <div>
<ul>
<li>item.name</li>
</ul>
<button onClick={() => addItem(item.id,'value name')}>Add</button>
</div>
})}
Something looks wrong in your example. I have added a complete exampl. You can maintain localStorage and State both. I hope this example helps you.
You mistake is that while adding new item you are pushing it to localStoage due to which react dom does not get rerendered. You have to update the value of state for that.
class App extends React.Component {
constructor() {
super();
this.state = {
categories: [
{
name: "Hello",
id: 1
},
{
name: "World",
id: 2
}
]
};
this.addItem = this.addItem.bind(this);
this.SaveToLocalStorage = this.SaveToLocalStorage.bind(this);
}
SaveToLocalStorage() {
const categories = this.state.categories;
localStorage.setItem("categories", JSON.stringify(categories));
}
addItem(id, name) {
const categories = this.state.categories;
categories.push({
name: name,
id: id
});
this.setState({ categories });
//localStorage.setItem("categories", JSON.stringify(categories));
}
render() {
let categories = this.state.categories;
const test = categories.map(item => (
<div key={item.id}>
<li>{item.name}</li>
</div>
));
return (
<div>
{test}
<button onClick={() => this.addItem(Date.now(), "Item")}>
Click to Add More
</button>
<button onClick={() => this.SaveToLocalStorage()}>
Save To LocalStorage{" "}
</button>
</div>
);
}
}
ReactDOM.render( < App / > , document.getElementById("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>
I guess this is what you are asking for. You just need to set it to state and re-render it when ever you are trying to add an element to list/array. I don't know why you are setting it to local storage but you can do it from state directly if your intention is to just store the previous array for future additions.
import React, { Component } from "react";
class App extends Component {
state = {};
constructor(props){
super(props);
this.state={
arr = []
}
}
addItem(id, name) {
const array = JSON.parse(localStorage.getItem("categories"));
array.push({
name: name,
id: id
});
//<li>{name}</li> push this into last array
localStorage.setItem("categories", JSON.stringify(array));
this.setState({arr:array});
}
renderList = () => {
return this.state.array.map(function(item, key) {
return (
<div>
<ul>
<li>item.name</li>
</ul>
<button onClick={() => addItem(item.id, "value name")}>Add</button>
</div>
);
});
};
render() {
return <div>{this.renderList()}</div>;
}
}
export default App;

React updating shopping cart when item selected

I am new to react and I am working on a flight project.
I am attempting to update a shopping cart when items are selected. I am aware the structure of the code might not be the best way, but this is what I have so far.
Export class DestinationPrices extends React.Component {
constructor(props) {
super(props);
this.state = {
flightData: [],
checked:false,
data:'',
cart:[]
};
this.handleClick = this.handleClick.bind(this);
this.handleAddToCart = this.handleAddToCart.bind(this);
}
NavCart() {
return (
<div className="Nav" >
<Card body >
<CardTitle ><h3><b>Flights Selected : </b></h3></CardTitle>
<CardText >
<span className="fa fa-cart-plus fa-2x"> {this.props.cart.length}</span>
</CardText>
</Card>
</div>
)
}
That is the cart itself which should update number of items when selected.
Below is the Select method which you can select the different cards.
Select(FD) {
this.state={route:''};
return (
<div>
{FD.FlightID}
<label>
<Checkbox id={FD.FlightID}
name={FD.FlightID}
checked={this.setState.route}
onChange={(()=> this.handleCheckboxChange(FD.FlightID))}
handleClick={()=>{this.handleClick(FD.FlightID)}}
/>
<span>Select</span>
</label>
</div>
)
}
These are the functions I have to handle the changes
handleCheckboxChange =(id) =>{
var data;
const selected = (e => e.FlightID = id);
this.handleAddToCart(id);
};
handleAddToCart(flight) {
const cartItem = this.state.cart.find(x => x.id === flight.id);
this.setState({cart: [...this.state.cart, flight]})
}
handleClick(flight) {
this.handleAddToCart(flight)
}
If anyone is able to help it would be greatly appreciated.

Mapping Nested Checkbox not working ReactJS

I have a function which triggers children checkboxes once main checkbox is checked, and all these checkboxes are mapped from JSON. The main checkboxes (Highest order) and all of its children checkboxes (2nd order) under them are shown on check and its working great, what i am trying to show is the children of those children of the main checkboxes (3rd order).
Basically to show all three orders under each other on check, and add the 3rd order to my current code, so Options Group shows Options, and under Options is what i want to show, which are Option 1, Option 2, option 3 and so on..
The checkbox values are passed as props from Checkbox.js to Itemlist.js where the fetch/map happens.
As I was trying to achieve this, I have been able to show each of these 3rd order checkboxes but each one alone instead of showing them as nested checkboxes. I've tried to include it in the existing mapping function to show them all as nested checkboxes as mentioned but it couldn't work it only works if it was mapped alone instead of the current mapped path which is const selectedItem. while the mapping path of the targeted checkboxes (3rd level) are added in Itemlist.js as const selectedMod,
Main Snippet : https://codesandbox.io/embed/6jykwp3x6n?fontsize=14
What I reached for so far to show the targeted checkboxes but individually: https://codesandbox.io/embed/o932z4yr6y?fontsize=14
Checkbox.js
import React from "react";
import "./Checkbox.css";
class Checkboxes extends React.Component {
constructor(props) {
super(props);
this.state = {
currentData: 0,
limit: 2,
checked: false
};
}
selectData(id, event) {
let isSelected = event.currentTarget.checked;
if (isSelected) {
if (this.state.currentData < this.props.max) {
this.setState({ currentData: this.state.currentData + 1 });
} else {
event.preventDefault();
event.currentTarget.checked = false;
}
} else {
if (this.state.currentData >= this.props.min) {
this.setState({ currentData: this.state.currentData - 1 });
} else {
event.preventDefault();
event.currentTarget.checked = true;
}
}
}
render() {
const input2Checkboxes =
this.props.options &&
this.props.options.map(item => {
return (
<div className="inputGroup2">
{" "}
<div className="inputGroup">
<input
id={this.props.childk + (item.name || item.description)}
name="checkbox"
type="checkbox"
onChange={this.selectData.bind(
this,
this.props.childk + (item.name || item.description)
)}
/>
<label
htmlFor={this.props.childk + (item.name || item.description)}
>
{item.name || item.description}{" "}
</label>
</div>
</div>
);
});
return (
<form className="form">
<div>
{/** <h2>{this.props.title}</h2>*/}
<div className="inputGroup">
<input
id={this.props.childk + this.props.name}
name="checkbox"
type="checkbox"
checked={this.state.checked}
onChange={this.selectData.bind(
this,
this.props.childk + this.props.uniq
)}
onChange={() => {
this.setState({
checked: !this.state.checked,
currentData: 0
});
}}
/>
<label htmlFor={this.props.childk + this.props.name}>
{this.props.name}{" "}
</label>
</div>{" "}
{this.state.checked ? input2Checkboxes : undefined}
</div>
</form>
);
}
}
export default Checkboxes;
Itemlist.js Where the mapping function happen
...
const selectedItem =
selectedChild.children && selectedChild.children.length
? selectedChild.children[this.state.itemSelected]
: null;
...
<div>
{selectedItem &&
selectedItem.children &&
selectedItem.children.map((item, index) => (
<Checkboxes
key={index}
name={item.name || item.description}
myKey={index}
options={item.children}
childk={item.id}
max={item.max}
min={item.min}
/>
))}
</div>
...

Categories

Resources