I did initial state for select single checkbox .Here is my intial state
this.state = {
fruites: [
{ id: 1 , value: "banana", isChecked: false },
{ id: 2, value: "apple", isChecked: false },
{ id: 3,value: "mango", isChecked: false },
{ id: 4, value: "grap", isChecked: false }
]
};
}
Method: I just this for selected all checkbox
handleAllChecked = id => event => {
let fruites = this.state.fruites;
fruites.forEach(fruite => {
data.filter(item =>
fruite.isChecked = event.target.checked;
});
});
this.setState({ fruites: fruites });
};
I just this method for individual checkbox .
handleCheckChieldElement = event => {
let fruites = this.state.fruites;
fruites.forEach(fruite => {
if (fruite.value === event.target.value)
fruite.isChecked = event.target.checked;
});
this.setState({ fruites: fruites });
};
Render:Here is my UI, I want to select All checkbox based on group . For example , I have got two group of value - such as Group , Topgroup. The problem is that , When I click on the group , it will select All checkbox including Topgroup and also I click banana , it will select all banana , I don't want to get all banana when click on one item. I don't to want to get topgroup checkbox when I select on the group.
{[{ id: 1, name: "group" }, { id: 2, name: "topGropup" }].map(item => (
<div>
<input
type="checkbox"
onChange={this.handleAllChecked(item.id)}
value="checkedall"
/>{" "}
{item.name}
<ul>
{this.state.fruites.map((fruite, index) => {
return (
<CheckBox
key={index}
handleCheckChieldElement={this.handleCheckChieldElement}
{...fruite}
/>
);
})}
</ul>
</div>
))}
</div>
How can I resolve this problem . Here is my codesanbox : https://codesandbox.io/s/react-multi-select-checkbox-or6ko
Here, I edited your codesandbox: https://codesandbox.io/s/react-multi-select-checkbox-bbuky
Basically you have 8 checkboxes, even though its 4 items displayed, duplicated for each group.
I added the 4 missing items in your state, but you'd actually want some kind of factory function that lets you create your state given the groups you have.
I had to edit some of your values since you were relying on stuff that now is not unique anymore, like value and use the group's id for example to create a unique identifier groupId-itemId.
Memory pointer to the same list
The groups in the app have the same pointer to memory list of fruits.
because of that the updates will affect on both groups.
See how I fixed it:
https://codesandbox.io/s/react-multi-select-checkbox-r29d1
I found some things in the app that can be improve so I improve them for example:
label to input checkbox to be able to click also on the text
I am here if you have any problem, I suggest you to learn Hooks.
Related
I have a problem with my ReactJS App. I want to get values of checked radio buttons and after selecting I want to display the values of selected radio buttons.
The form is generated from a json file
[
{
variantId: 1,
variantName: 'Size',
variantOptions: [
{
variantOptionId: 1,
variantOptionName: 'S',
variantOptionPriceChange: 4.5
},
{
variantOptionId: 2,
variantOptionName: 'M',
variantOptionPriceChange: 4.5
},
]
},
{
variantId: 2,
variantName: 'Color',
variantOptions: [
{
variantOptionId: 3,
variantOptionName: 'Red',
variantOptionPriceChange: 4.5
},
{
variantOptionId: 4,
variantOptionName: 'Blue',
variantOptionPriceChange: 4.5
},
]
}
]
Demo of the problem is visible here: https://codesandbox.io/s/epic-http-bgmx3?file=/src/App.js
I want to display all selected items, not only the last one.
The problem is in this part of code, but I dont know how to rewrite it to achieve the desired behavior.
const addOption = (o) => {
setOptions({
optionId: o.variantOptionId,
optionName: o.variantOptionName,
optionPriceChange: o.variantOptionPriceChange
});
};
Thank you for your help, hope I described it clearly.
Simplest solution would be creating an object in useState with props keys for each variant and then store the selected option of that variant in related object prop
It should work like this:
export default function App() {
const [options, setOptions] = useState({});
const addOption = (name, o) => {
setOptions({ ...options, [name]: o });
};
return (
<div className="App">
{variants.map((variant, index) => {
return (
<Variant
options={options}
variant={variant}
addOption={addOption}
key={index}
/>
);
})}
<h3>
Selected variants are:
<ul>
{Object.keys(options).map((name, i) => {
return (
<li key={i}>
{name}: {options[name].variantOptionName}
</li>
);
})}
</ul>
</h3>
</div>
);
}
I am having a dropdown where a user can add multiple dropdowns and select a value in it. While making a GET request, i wanted to keep the selected value in the dropdown, but not sure how to do it. I am able to make the selected value in a single dropdown, but finding it difficult to keep the selected value in multiple dropdowns.
I will be getting the value in an array like this
values = ["English","Ukraine","Japnese","Korean"];
Then in Select Dropdown for setting the single value i have written it like this:
options = [
{value: "english", label: "English"},
{value: "ukraine", label: "Ukraine"},
{value: "japnese", label: "Japnese"},
{value: "korean", label: "Korean"},
{value: "french", label: "French"}
];
<Select
className="profile-module-select-container"
classNamePrefix="profile-module-select"
options={options}
onChange={selected => {
this.handleDropdownSelect(selected, formKey);
}}
onMenuOpen={(e, i, o) => {
this.setState({
selectMenuOpen: true
});
}}
onMenuClose={() => {
this.setState({
selectMenuOpen: false
});
}}
name={name}
value={options.filter((items) => { return items.value === values })}
/>
values is an array and you would have to loop it over as well and filter it against Options . Considering the current implementation, it would be a nested loop, yes.
As stated in the title I'm trying to change the state of an object nested in an array of objects. I just can not get this to work. I've added a sample of what I'm trying to do in a codesandbox.
I'm using a Material-UI component call ToggleButton (link to demo ToggleButton). I want to change the state to toggle the buttons in the group. I was able to get this working for a create function but can not get it working for my update function.
Trying to change the values of the object in the array is just not working for me. Below are some things I've tried to no success. I want to change the IsTrue: so I can toggle the button to display the users selection.
setAppetizer(true);
setRecipeObjectState({
...recipeObjectState,
Category: [
...recipeObjectState.Category,
{
IsTrue: appetizer,
category: "Appetizer",
},
],
});
This just adds more buttons to my button group.
setAppetizer(true);
setRecipeObjectState((prevState) => ({
...prevState,
Category: [
{
IsTrue: appetizer,
category: "Appetizer",
},
],
}));
I'm just lost now at this point. I just want to also state that this is my first React project that is not just a sandbox for learning the framework and I'm also a jr. developer trying to learn. I have search stackoverflow and nothing has helped me out. I hope I have included enough information for someone to help out.
Your state and app appear to be very convoluted, but the general idea when updating nested array state is to shallowly copy the state at each level where an update is being made. Use array::map to map the Category property to a new array object reference and when the category matches toggle the IsTrue "selected" property.
setRecipeObjectState((prevState) => ({
...prevState,
Category: prevState.Category.map((category) =>
category.category === newCategory // <-- newCategory value from toggled button
? {
...category,
IsTrue: !category.IsTrue
}
: category
)
}));
Since your "selected" calculation is selected={Boolean(item.IsTrue)} you'll want to ensure your IsTrue element values are actually togglable, i.e. just store the boolean value right in the array.
const recipeObject = {
AuthorId: authorId,
BookAuthor: bookAuthor,
BookTitle: bookTitle,
Calories: parseInt(calories),
Category: [
{
IsTrue: false,
category: "Appetizer"
},
{
IsTrue: false,
category: "Breakfast"
},
{
IsTrue: false,
category: "Soup / Salad"
},
{
IsTrue: false,
category: "Vegetarian"
},
{
IsTrue: true,
category: "Meat (Beef, Pork, Chicken)"
},
{
IsTrue: false,
category: "Fish"
},
{
IsTrue: false,
category: "Dessert"
}
],
Description: description,
DurationInMinCook: parseInt(durationInMinCook),
DurationInMinPrep: parseInt(durationInMinPrep),
ImageUrl: imageUrl,
Ingredients: addedIngredients, // array
Instructions: addedInstructions, // array
IsRecipe: true,
Likes: 0,
RecipeId: selectedRecipeId,
ServingSize: parseInt(servingSize),
Title: title,
YouTubeUrl: youTubeUrl
};
You mutating the same reference, you need to render a copy or the component won't render (shallow comparison):
Try updating state like this.
const oldState = recipeObjectState;
oldState.Category = [
{
IsTrue: appetizer,
category: "Appetizer"
}
];
setRecipeObjectState(oldState);
I didn't try your component because it's huge.
Updating a single object property in an array of objects seems to be a very common use-case. Here is generally how you do that. Suppose id is a unique identifier of each object and that we want to toggle selected:
import React, { useState } from "react";
import "./styles.css";
import faker from "faker";
const array = [];
for (let id = 1; id < 10; id++) {
array.push({
id,
name: faker.name.firstName(),
age: faker.random.number(100),
selected: false
});
}
export default function App() {
const [list, setList] = useState(array);
const onClick = (id) => (event) => {
setList((list) =>
list.map((item) =>
item.id === id ? { ...item, selected: !item.selected } : item
)
);
};
return (
<div className="App">
Click on a item:
<ul>
{list.map(({ id, name, age, selected }) => (
<li key={id} onClick={onClick(id)} className="item">
{name} {age}
{selected ? " ✅" : null}
</li>
))}
</ul>
</div>
);
}
https://codesandbox.io/s/xenodochial-river-9sq6g?file=/src/App.js:0-825
Basically, I want to use the react-select library and use the isMulti prop, but the problem with that after selecting an option, the value would be deleted. As you can see below with the provided images, as soon as I click "US: 1" that option would go away. But for the app I'm trying to build, it's certainly possible for a customer to want 2 of the same sizes. Therefore they would pick 2 "US: 1" and it automatically sets the quantity to 2. The problem is that as soon as they pick "US: 1" that option goes away.
This is all I currently have now.
const options = [
{value: 1, label: "US: 1"},
{value: 1.25, label: "US: 1.25"},
{value: 1.5, label: "US: 1.5"},
{value: 1.75, label: "US: 1.75"},
{value: 2, label: "US: 2"},
{value: 2.25, label: "US: 2.25"},
]
class Details extends Component {
state={
selectedOption: []
}
handleChange = (selectedOption) => {
this.setState({ selectedOption: selectedOption });
}
render() {
<Select isMulti={true} isSearchable={true} onClick={value.changeSize(id, selectedOption)} value={selectedOption} onChange={this.handleChange} options={options}></Select>
}
}
Here's an example of what I'm talking about. "US: 1" goes away when it's clicked when I want that option to stay. I'm thinking it alters my "options" array and displaying the new one that doesn't have the clicked option. If I can somehow keep feeding it these original values after every single on onChange that would be awesome. I'm not sure how to dig into the library on how to do it or if it's even possible.
https://www.npmjs.com/package/react-select
Here how I would do it:
class Details extends Component {
state = {
selectedOption: []
};
handleChange = selectedOption => {
const newSelectedOption = selectedOption.map(opt => ({
label: opt.label,
innerValue: opt.value,
// I set a random value because it is needed to be able to delete the value without deleting all of them
value: Math.random()
}));
this.setState({ selectedOption: newSelectedOption });
};
render() {
return (
<Select
isMulti={true}
isSearchable={true}
value={this.state.selectedOption}
onChange={this.handleChange}
options={options}
/>
);
}
}
The idea is not to use value as it's original goal. When a label props is passed to value inside Select it still displays it correctly. So you will base yourself on innerValue and trick react-select.
Here a live example
I guess all you need is to add hideSelectedOptions={false} to <Select />.
Like:
<Select
isMulti={true}
hideSelectedOptions={false}
options={options}
...
/>
In my react-app i have a list that is rendered dynamically from an array, each item has a checkbox and an input, the input by default is disabled, when i click on the checkbox this input should be enabled if it meets a specific condition, i have managed to do some of the work, but I'm facing some issues like when i click on one of the checkboxes all inputs get enabled, and this input has a value i want to be able to edit it but i can't here is the code:
Initial state
cards: [],
disabledInput: false
Mapping the list:
return this.state.cards.map(card => (
<Checkbox key={card.id} onClick={this.setState({ disabledInput: true })} />
<Input value={this.state.card.name} disabled={this.state.disabledInput} onChange={e => this.setState({ text: e.target.value })} />
));
You need to keep the initial disable states of each checkbox true as an array and map that individually into each checkbox.
cards = [{
name: 'card 1',
disabledInput: true
}, {
name: 'card 2',
disabledInput: true
}]
changeDisableState = (i) => {
let cards = this.state.cards;
cards[i].disabledInput = !cards[i].disabledInput;
this.setState({cards});
}
return this.state.cards.map((card, i) => (
<Checkbox key={card.id} onClick={() => this.changeDisableState(i)} />
<Input value={card.name} disabled={card.disabledInput}/>
));
Edited: Instead of a separate array you can keep a disable field inside the card state itself.
Each checkbox should have a boolean to manage its own state (checked or not). I created a Codesandbox that should solve your problem
You need to maintain a disabledInput flag for each card, at the minute you only have one across all cards.
Your card state should look something like -
cards = [{
name: 'card 1',
disabledInput: false
}, {
name: 'card 2',
disabledInput: true
}]