4

I am having 4 buttons each button have name id and selected boolean flag.

What I am trying to achieve is, on click of button, boolean button flag should be changed of that particular button. For this, I need to setState in map function for that particular button Id.

My issue is I am unable to setState in map function for that particular clicked button, its btnSelected should be changed

My aim is to create a multi-select deselect button.Its kind of interest selection for the user and based on that reflect the UI as well my array. Here is my code.

Thanks in anticipation.

import React, { Component } from "react";
import { Redirect } from "react-router-dom";

export default class Test extends Component {
  constructor(props, context) {
    super(props, context);

    this.handleChange = this.handleChange.bind(this);
    this.state = {
      value: "",
      numbers: [1, 2, 3, 4, 5],
      posts: [
        {
          id: 1,
          topic: "Animal",
          btnSelected: false
        },
        {
          id: 2,
          topic: "Food",
          btnSelected: false
        },
        {
          id: 3,
          topic: "Planet",
          btnSelected: false
        },
        { id: 4, topic: "Nature", btnSelected: false }
      ],
      allInterest: []
    };
  }

  handleChange(e) {
    //console.log(e.target.value);
    const name = e.target.name;
    const value = e.target.value;
    this.setState({ [name]: value });
  }

  getInterest(id) {
    this.state.posts.map(post => {
      if (id === post.id) {
        //How to setState of post only btnSelected should change
      }
    });
    console.log(this.state.allInterest);
    if (this.state.allInterest.length > 0) {
      console.log("Yes we exits");
    } else {
      console.log(id);
      this.setState(
        {
          allInterest: this.state.allInterest.concat(id)
        },
        function() {
          console.log(this.state);
        }
      );
    }
  }

  render() {
    return (
      <div>
        {this.state.posts.map((posts, index) => (
          <li
            key={"tab" + index}
            class="btn btn-default"
            onClick={() => this.getInterest(posts.id)}
          >
            {posts.topic}
            <Glyphicon
              glyph={posts.btnSelected === true ? "ok-sign" : "remove-circle"}
            />
          </li>
        ))}
      </div>
    );
  }
}
Tomasz Mularczyk
  • 34,501
  • 19
  • 112
  • 166
Mohammed Sabir
  • 157
  • 2
  • 2
  • 17

2 Answers2

5

Here's how you do something like this:

class App extends Component {
  state = {
    posts: [{
      name: 'cat',
      selected: false,
    }, {
      name: 'dog',
      selected: false
    }]
  }

  handleClick = (e) => {
    const { posts } = this.state;
    const { id } = e.target;
    posts[id].selected = !this.state.posts[id].selected
    this.setState({ posts })
  }

  render() {
    return (
      <div>
        <form>
          {this.state.posts.map((p, i) => {
            return (
              <div>
                <label>{p.name}</label>
                <input type="radio" id={i} key={i} checked={p.selected} onClick={this.handleClick} />
              </div>
            )
          })}
        </form>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

Working example here.

Colin Ricardo
  • 16,488
  • 11
  • 47
  • 80
0

You can do this by passing the index from the map into each button's handleClick function, which would then return another function that can be triggered by an onClick event.

In contrast to Colin Ricardo's answer, this approach avoids adding an id prop onto each child of the map function that is only used for determining the index in the handleClick. I've modified Colin's example here to show the comparison. Notice the event parameter is no longer necessary.

class App extends Component {
  state = {
    posts: [{
      name: 'cat',
      selected: false,
    }, {
      name: 'dog',
      selected: false
    }]
  }

  handleClick = (index) => () => {
    const { posts } = this.state;
    posts[index].selected = !this.state.posts[index].selected
    this.setState({ posts })
  }

  render() {
    return (
      <div>
        <form>
          {this.state.posts.map((p, i) => {
            return (
              <div>
                <label>{p.name}</label>
                <input type="checkbox" key={i} checked={p.selected} onClick={this.handleClick(i)} />
              </div>
            )
          })}
        </form>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

Working example here