0

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

5 Answers 5

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this worked. Obviously had to merge in my own code.
1

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

4 Comments

You'll probably get an error saying this.state is not iterable.
@Andy, why do you say so, SelectedFriendIds is an array ??
Considering you just changed [...this.state] to this.state you know exactly what I meant.
@Andy, I just noticed it. That was a big blunder
0

You can simply use array.push for adding ids on check array.filter to retrieve single id and array.slice to remove single id.

Comments

0

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)

Comments

0

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.