Edinho Rodrigues
Edinho Rodrigues

Reputation: 366

reactjs onclick inside map

I have an array that renders a button and when I click this button I need to only change the item of this array connected to that button, adding the name of the user connected to that localStorage. Currently, when I click the button it is changing all the items in the array. To help, I gave a functional example of what I need at this link: https://codesandbox.io/embed/lots-tojln
I need the buttons to work separately

import React from "react";

import "./styles.css";
const separator = "/";
export default class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      toggleButton: true,
      lots: [
        {
          lotNumber: "1",
          lotPrice: "10.00",
          lotPriceTax: "0.00",
          lotType: "U",
          lotUniqueNumber: "xZ38Dw7bDwD33z469xcB4yy3b64D3z",
          quantity: 2,
          ticketName: "Camarote",
          ticketPrevenda: "false",
          ticketUniqueNumber: "3WaDBCcawdzyZdAZYBCBz1zb170x47",
          total: 20,
          totalLotPrice: 10
        },
        {
          lotNumber: "1",
          lotPrice: "10.00",
          lotPriceTax: "0.00",
          lotType: "M",
          lotUniqueNumber: "xZ38Dw7bDwD33z469xcB4yy3b64D3z",
          quantity: 2,
          ticketName: "Camarote",
          ticketPrevenda: "false",
          ticketUniqueNumber: "3WaDBCcawdzyZdAZYBCBz1zb170x47",
          total: 20,
          totalLotPrice: 10
        }
      ],
      userName: ""
    };
    this.ticketsCheckDocument = this.ticketsCheckDocument.bind(this);
    this.ticketChange = this.ticketChange.bind(this);
  }

  ticketsCheckDocument(e) {
    const [ticketUniqueNumber, lotType, Name] = e.target.value.split(separator);
    console.log(ticketUniqueNumber);
    console.log(lotType);
    console.log(Name);
    this.setState({ toggleButton: false });
    this.setState({ userName: Name });
  }

  ticketChange() {
    this.setState({ toggleButton: true });
    this.setState({ userName: "" });
  }

  render() {
    const lots = this.state.lots.map((lot, l) => (
      <div className="box-ticket" key={l}>
        <div className="box-vertical">
          <h4 className="ticket-type">
            {lot.lotType === "U"
              ? "Unissex"
              : lot.lotType === "M"
              ? "Male"
              : "Female"}{" "}
            <br />
            <small>R$ {lot.lotPrice}</small>
          </h4>
        </div>
        <div className="box-text">
          <h4 className="ticket-user-name">{this.state.userName}</h4>
          <p className="text-center">
            The invitations are nominal. <br />
            Please indicate below who will use this invitation
          </p>
          <div className="box-button">
            {this.state.toggleButton ? (
              <div>
                <button
                  type="button"
                  className="btn btn-primary"
                  value={`${lot.ticketUniqueNumber}${separator}${
                    lot.lotType
                  }${separator}Teste ${l}`}
                  onClick={this.ticketsCheckDocument}
                >
                  It's My
                </button>
                <button type="button" className="btn btn-primary">
                  I'll Give
                </button>
              </div>
            ) : (
              <button
                type="button"
                className="btn btn-primary"
                onClick={this.ticketChange}
              >
                Change
              </button>
            )}
          </div>
        </div>
      </div>
    ));
    return <div>{lots}</div>;
  }
}

Upvotes: 1

Views: 1181

Answers (2)

Junius L
Junius L

Reputation: 16122

You can move the whole code a component and let each component manage it's state.

class Invitation extends React.Component {
  state = {
    toggleButton: true,
    userName: '',
  }

  ticketsCheckDocument = (e) => {
    const [ticketUniqueNumber, lotType, Name] = e.target.value.split(separator);
    console.log(ticketUniqueNumber);
    console.log(lotType);
    console.log(Name);
    this.setState({ toggleButton: false });
    this.setState({ userName: Name });
  }

  ticketChange = () => {
    this.setState({ toggleButton: true });
    this.setState({ userName: "" });
  }

  render() {

    const { lot, index } = this.props;

    return (
      <div className="box-ticket">
        <div className="box-vertical">
          <h4 className="ticket-type">
            {lot.lotType === "U"
              ? "Unissex"
              : lot.lotType === "M"
                ? "Male"
                : "Female"}{" "}
            <br />
            <small>R$ {lot.lotPrice}</small>
          </h4>
        </div>
        <div className="box-text">
          <h4 className="ticket-user-name">{this.state.userName}</h4>
          <p className="text-center">
            The invitations are nominal. <br />
            Please indicate below who will use this invitation
          </p>
          <div className="box-button">
            {this.state.toggleButton ? (
              <div>
                <button
                  type="button"
                  className="btn btn-primary"
                  value={`${lot.ticketUniqueNumber}${separator}${lot.lotType
                    }${separator}Teste ${index}`}
                  onClick={this.ticketsCheckDocument}
                >
                  It's My
                </button>
                <button type="button" className="btn btn-primary">
                  I'll Give
                </button>
              </div>
            ) : (
                <button
                  type="button"
                  className="btn btn-primary"
                  onClick={this.ticketChange}
                >
                  Change
              </button>
              )}
          </div>
        </div>
      </div>
    )
  }
}

DEMO

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<style>
.App {
  font-family: sans-serif;
  text-align: center;
}

.box-ticket {
  background-image: url(./images/ticket03.png);
  background-repeat: no-repeat;
  background-size: 100% 140px;
  background-position-x: 1px;
  background-color: #000;
}

.box-vertical {
  transform: rotate(270deg);
  width: 160px;
  position: relative;
  float: left;
  top: 50px;
  left: -15px;
  text-align: center;
  font-size: 18px;
  font-weight: 700;
  text-transform: uppercase;
}

.box-vertical h3 {
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 0;
}

.box-vertical h4 {
  color: #fff;
  font-size: 16px;
}

.box-vertical .ticket-type small {
  color: #000;
  font-weight: bold;
}

.box-ticket .box-text {
  height: 140px;
  margin-left: 120px;
  padding: 5px 10px;
  background-color: transparent;
  color: #fff !important;
  border-bottom-right-radius: 3px;
  border-top-right-radius: 3px;
  margin-bottom: 10px;
}

.box-ticket .box-text p {
  font-size: 12px;
}

.box-text .box-button {
  display: flex;
  justify-content: center;
  align-items: center;
}

.box-text .box-button button {
  padding: 5px;
  margin: 0;
  margin-right: 5px;
  background-color: rgba(230, 45, 85, 0.85);
  border-color: transparent;
}
.box-text form > button {
  padding: 5px;
  margin: 0;
  margin-right: 5px;
  background-color: rgba(230, 45, 85, 0.85);
  border-color: transparent;
}

.box-text .box-button .btn-primary:not(:disabled):not(.disabled):active {
  background-color: rgba(230, 45, 85, 1);
  border-color: transparent;
}

.box-text .box-button .btn:focus {
  outline: none;
  box-shadow: none;
}

.ticket-user-name {
  text-align: center;
  margin-top: 5px;
  margin-bottom: 5px;
  min-height: auto;
  height: 15px;
  left: -10px;
  position: relative;
}

hr {
  margin-top: 0;
}

.installments-warning {
  color: #737373;
  text-align: center;
  font-size: 14px;
  margin-top: 0.5em;
  font-weight: 400;
}

.total-interest {
  margin-top: 0.5em;
  text-align: center;
  font-size: 18px;
  color: #737373;
}

</style>
<div id="root"></div>

<script type="text/babel">

class Invitation extends React.Component {
  state = {
    toggleButton: true,
    userName: '',
  }

  ticketsCheckDocument = (e) => {
    const [ticketUniqueNumber, lotType, Name] = e.target.value.split(separator);
    console.log(ticketUniqueNumber);
    console.log(lotType);
    console.log(Name);
    this.setState({ toggleButton: false });
    this.setState({ userName: Name });
  }

  ticketChange = () => {
    this.setState({ toggleButton: true });
    this.setState({ userName: "" });
  }

  render() {

    const { lot, index } = this.props;

    return (
      <div className="box-ticket">
        <div className="box-vertical">
          <h4 className="ticket-type">
            {lot.lotType === "U"
              ? "Unissex"
              : lot.lotType === "M"
                ? "Male"
                : "Female"}{" "}
            <br />
            <small>R$ {lot.lotPrice}</small>
          </h4>
        </div>
        <div className="box-text">
          <h4 className="ticket-user-name">{this.state.userName}</h4>
          <p className="text-center">
            The invitations are nominal. <br />
            Please indicate below who will use this invitation
              </p>
          <div className="box-button">
            {this.state.toggleButton ? (
              <div>
                <button
                  type="button"
                  className="btn btn-primary"
                  value={`${lot.ticketUniqueNumber}${separator}${lot.lotType
                    }${separator}Teste ${index}`}
                  onClick={this.ticketsCheckDocument}
                >
                  It's My
                    </button>
                <button type="button" className="btn btn-primary">
                  I'll Give
                    </button>
              </div>
            ) : (
                <button
                  type="button"
                  className="btn btn-primary"
                  onClick={this.ticketChange}
                >
                  Change
                  </button>
              )}
          </div>
        </div>
      </div>
    )
  }
}


const separator = "/";
class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      toggleButton: true,
      lots: [
        {
          lotNumber: "1",
          lotPrice: "10.00",
          lotPriceTax: "0.00",
          lotType: "U",
          lotUniqueNumber: "xZ38Dw7bDwD33z469xcB4yy3b64D3z",
          quantity: 2,
          ticketName: "Camarote",
          ticketPrevenda: "false",
          ticketUniqueNumber: "3WaDBCcawdzyZdAZYBCBz1zb170x47",
          total: 20,
          totalLotPrice: 10
        },
        {
          lotNumber: "1",
          lotPrice: "10.00",
          lotPriceTax: "0.00",
          lotType: "M",
          lotUniqueNumber: "xZ38Dw7bDwD33z469xcB4yy3b64D3z",
          quantity: 2,
          ticketName: "Camarote",
          ticketPrevenda: "false",
          ticketUniqueNumber: "3WaDBCcawdzyZdAZYBCBz1zb170x47",
          total: 20,
          totalLotPrice: 10
        }
      ],
      userName: ""
    };
    this.ticketsCheckDocument = this.ticketsCheckDocument.bind(this);
    this.ticketChange = this.ticketChange.bind(this);
  }

  ticketsCheckDocument(e) {
    const [ticketUniqueNumber, lotType, Name] = e.target.value.split(separator);
    console.log(ticketUniqueNumber);
    console.log(lotType);
    console.log(Name);
    this.setState({ toggleButton: false });
    this.setState({ userName: Name });
  }

  ticketChange() {
    this.setState({ toggleButton: true });
    this.setState({ userName: "" });
  }

  render() {
    const lots = this.state.lots.map((lot, l) => (<Invitation index={l} lot={lot} key={l} />));
    return <div>{lots}</div>;
  }
}


ReactDOM.render(<Card />, document.getElementById("root"));
</script>

Upvotes: 1

Ace
Ace

Reputation: 1146

You need to make userName and toggleButton properties of each object in lots. Then you can pass the index of the lot to the ticketsCheckDocument to update the corresponding lot element.

Try this:

import React from "react";

import "./styles.css";
const separator = "/";
export default class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {

      lots: [{
          lotNumber: "1",
          lotPrice: "10.00",
          lotPriceTax: "0.00",
          lotType: "U",
          lotUniqueNumber: "xZ38Dw7bDwD33z469xcB4yy3b64D3z",
          quantity: 2,
          ticketName: "Camarote",
          ticketPrevenda: "false",
          ticketUniqueNumber: "3WaDBCcawdzyZdAZYBCBz1zb170x47",
          total: 20,
          totalLotPrice: 10,
          toggleButton: true,
          userName: ""
        },
        {
          lotNumber: "1",
          lotPrice: "10.00",
          lotPriceTax: "0.00",
          lotType: "M",
          lotUniqueNumber: "xZ38Dw7bDwD33z469xcB4yy3b64D3z",
          quantity: 2,
          ticketName: "Camarote",
          ticketPrevenda: "false",
          ticketUniqueNumber: "3WaDBCcawdzyZdAZYBCBz1zb170x47",
          total: 20,
          totalLotPrice: 10,
          toggleButton: true,
          userName: ""
        }
      ],

    };
    this.ticketsCheckDocument = this.ticketsCheckDocument.bind(this);
    this.ticketChange = this.ticketChange.bind(this);
  }

  ticketsCheckDocument(e, i) {
    const [ticketUniqueNumber, lotType, Name] = e.target.value.split(separator);
    console.log(ticketUniqueNumber);
    console.log(lotType);
    console.log(Name);
    const lots = [...this.state.lots];
    lots[i].toggleButton = false;
    lots[i].userName = Name;
    this.setState({
      lots
    })
  }

  ticketChange() {
    this.setState({
      toggleButton: true
    });
    this.setState({
      userName: ""
    });
  }

  render() {
    const lots = this.state.lots.map((lot, l) => ( <
      div className = "box-ticket"
      key = {
        l
      } >
      <
      div className = "box-vertical" >
      <
      h4 className = "ticket-type" > {
        lot.lotType === "U" ?
        "Unissex" :
          lot.lotType === "M" ?
          "Male" :
          "Female"
      } {
        " "
      } <
      br / >
      <
      small > R$ {
        lot.lotPrice
      } < /small> <
      /h4> <
      /div> <
      div className = "box-text" >
      <
      h4 className = "ticket-user-name" > {
        this.state.userName
      } < /h4> <
      p className = "text-center" >
      The invitations are nominal. < br / >
      Please indicate below who will use this invitation <
      /p> <
      div className = "box-button" > {
        lot.toggleButton ? ( <
          div >
          <
          button type = "button"
          className = "btn btn-primary"
          value = {
            `${lot.ticketUniqueNumber}${separator}${
                    lot.lotType
                  }${separator}Teste ${l}`
          }
          onClick = {
            e => this.ticketsCheckDocument(e, i)
          } >
          It 's My <
          /button> <
          button type = "button"
          className = "btn btn-primary" >
          I 'll Give <
          /button> <
          /div>
        ) : ( <
          button type = "button"
          className = "btn btn-primary"
          onClick = {
            this.ticketChange
          } >
          Change <
          /button>
        )
      } <
      /div> <
      /div> <
      /div>
    ));
    return <div > {
      lots
    } < /div>;
  }
}

Upvotes: 1

Related Questions