Reputation: 309
I have a prop called friends which is being listed as a checkboxes (default: unselected).
Example output:
o Bob Smith
o Tom Brown
How can I save the id's of all the names that are selected?
E.g. both are ticked/selected -> ids 1 and 2 is stored.
This is what I have so far:
class SelectFriends extends Component {
constructor(props) {
super(props)
this.state = {
SelectedFriendsIds: [],
}
}
render() {
const { SelectedFriendsIds } = this.state
const { userId, friends, addFriendsTo } = this.props
return (
<div>
<SubHeader title="Add Friends..." />
<div>
{friends
.mapEntries(([friendId, frn]) => [
friendId,
<div key={friendId}>
<input
value={friendId}
type='checkbox'
// onChange={ () => console.log("do something")
defaultChecked={false} />
{frn.firstName} {frn.lastName}
</div>,
])
.toList()}
</div>
<div>
<Button style="blue" name="Done" onClick={() => addFriendsTo(SelectedFriendIds, userId)} />
</div>
</div>
)
}
}
export default SelectFriends
Upvotes: 0
Views: 8499
Reputation: 63524
Here's a slightly simplified version of your code with a new function handleChange
that is called every time a checkbox is checked/unchecked.
We take a copy of the state and extract selectedFriendsIds
. If an id is to be added to the state setState
is called with a new array of the new value merged into selectedFriendsIds
. If checkbox is unchecked the setState
is called with a filtered copy of selectedFriendsIds
instead.
You might want to run this snippet full page as it logs the state to the console after each change to show you the output.
class SelectFriends extends React.Component {
constructor(props) {
super(props);
this.state = { selectedFriendsIds: [] }
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const { checked, value } = e.target;
let { selectedFriendsIds } = this.state;
if (checked) {
selectedFriendsIds = [...selectedFriendsIds, value];
} else {
selectedFriendsIds = selectedFriendsIds.filter(el => el !== value);
}
this.setState({ selectedFriendsIds }, () => console.log(this.state));
}
render() {
const { friends } = this.props;
return (
<div>
<h2>Add Friends</h2>
{friends.map(({ friendId, frn }) => {
return (
<div key={friendId}>
<input value={friendId} type="checkbox" onChange={this.handleChange} />{frn}
</div>
);
})}
</div>
)
}
}
const friends = [
{ friendId: 1, frn: 'Bob' },
{ friendId: 2, frn: 'Davros' },
{ friendId: 3, frn: 'Daisy' }
];
ReactDOM.render(
<SelectFriends friends={friends} />,
document.getElementById('container')
);
<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="container"></div>
Also available in a jsfiddle.
Upvotes: 2
Reputation: 1
I would like to suggest a small improvement to the design of your component, which also resolves the problem of how to maintain state of selected friend IDs efficiently. Frankly, there is no need to maintain state of selected Ids. Instead, please maintain a state of friends collection - where each object representing a friend, has 'selected' property. This way, You'd be able to easily filter selected ones and send this information to upper component. Below is the code snippet explaining this fully:
import React, { Component } from 'react';
import * as _ from 'lodash';
import PropTypes from 'prop-types';
class FriendsList extends Component {
state = {
friends: []
}
constructor(props) {
super(props);
this.onAdd = this.onAdd.bind(this);
this.state.friends = [ {id: 1, name: 'John', selected: false},
{ id: 2, name: 'Ally', selected: false},
{ id: 3, name: 'Becky', selected: false},
{ id: 4, name: 'Frank', selected: false},
{ id: 5, name: 'Mark', selected: true},
{ id: 6, name: 'Alice', selected: true}
];
}
onCheckboxChange(event, n) {
n.selected = !n.selected;
this.forceUpdate();
}
onAdd() {
const selectedFriends = _.filter( this.state.friends, (friend) => {
return friend.selected === true;
});
this.props.onAdd(selectedFriends);
}
render() {
const { friends } = this.state;
return (
<div>
{friends.map(n => {
return (
<div key={n.id}>
{n.name} <input type="checkbox" onChange={(event) => this.onCheckboxChange(event, n)} checked={n.selected}/>
</div>
);
})}
<button onClick={this.onAdd}>Add Friends</button>
</div>
);
}
}
FriendsList.propTypes = {
onAdd: PropTypes.func,
};
export default FriendsList;
Upvotes: 0
Reputation: 281626
You need to check if the value is already in your selected list and add it if its not there else remove the value onChange event of the checkbox. Check the sample code below
class SelectFriends extends Component {
constructor(props) {
super(props)
this.state = {
SelectedFriendsIds: [],
}
}
onChange = (val) => {
const SelectedFriendsIds = [...this.state.SelectedFriendsIds];
const presentIndex = SelectedFriendsIds.indexOf(val)
if(presentIndex > 0) {
SelectedFriendsIds.splice(presentIndex, 1);
} else {
SelectedFriendsIds.push(val);
}
this.setState({SelectedFriendsIds})
}
render() {
const { SelectedFriendsIds } = this.state
const { userId, friends, addFriendsTo } = this.props
return (
<div>
<SubHeader title="Add Friends..." />
<div>
{friends
.mapEntries(([friendId, frn]) => [
friendId,
<div key={friendId}>
<input
value={friendId}
type='checkbox'
onChange={ () => this.onChange(friendId)
defaultChecked={false} />
{frn.firstName} {frn.lastName}
</div>,
])
.toList()}
</div>
<div>
<Button style="blue" name="Done" onClick={() => addFriendsTo(SelectedFriendIds, userId)} />
</div>
</div>
)
}
}
export default SelectFriends
Upvotes: 1
Reputation: 1704
the code can be modified like this
class SelectFriends extends Component {
constructor(props) {
super(props)
this.state = {
SelectedFriendsIds: {}, //CHANGING INTO OBJ FOR EASIER MANIPULATION
}
}
render() {
const { SelectedFriendsIds } = this.state
const { userId, friends, addFriendsTo } = this.props
return (
<div>
<SubHeader title="Add Friends..." />
<div>
{friends
.mapEntries(([friendId, frn]) => [
friendId,
<div key={friendId}>
<input
checked={friendId} //USE CHECKED ALWAYS FOR CHECKBOXES
type='checkbox'
onChange={(e) => {
let x = SelectedFriendsIds;
if (e.target.checked) {
x[friendId] = true;
}
else {
delete x[friendId];
}
this.setState({
SelectedFriendsIds: x
})
}} />
{frn.firstName} {frn.lastName}
</div>,
])
.toList()}
</div>
<div>
<Button style="blue" name="Done" onClick={() => addFriendsTo(SelectedFriendIds, userId)} />
</div>
</div>
)
}
}
export default SelectFriends
If you need array of selected friends, just use
Object.keys(this.state.SelectedFriendsIds)
Upvotes: 0
Reputation: 15821
You can simply use array.push for adding ids on check array.filter to retrieve single id and array.slice to remove single id.
Upvotes: 0