How to toggle a button in React list?

Viewed 1520

I render a React list and there is an Edit button in each list item. I wanted to toggle to switch from the data to the input form and back. Similar to this application in this article: https://medium.com/the-andela-way/handling-user-input-in-react-crud-1396e51a70bf. You can check out the demo at: https://codesandbox.io/s/fragrant-tree-0t13x.

This is where my React Component display the list:

import React, { Component } from "react";
import PriceBox from "../SinglePricebox/index";
// import SecurityForm from "../SecurityForm/index";
import AddPriceForm from "../AddPriceForm/index";
// import { uuid } from "uuidv4";

export default class PriceForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      priceArr: this.props.pricelist,
      // newPriceArr: this.props.updatePrice,
      showPricePopup: false,
      addPricePopup: false,
      isToggleOn: true,
      date: props.date || "",
      number: props.number || ""
    };
  }

  updateInput = ({ target: { name, value } }) =>
  this.setState({ [name]: value });

  togglePopup = () => {
    this.setState(prevState => ({
      showPopup: !prevState.showPopup 
    }));
  };

  togglePricePopup = () => {
    this.setState(prevState => ({
      showPricePopup: !prevState.showPricePopup
    }));
  };

  addPricePopup = () => {
    this.setState(prevState => ({
      addPricePopup: !prevState.addPricePopup
    }));
  };

    /* adds a new price to the list */
    addPrice = newPrice => {
      this.setState(prevState => ({
        addPricePopup: !prevState.addPricePopup,
        // spreads out the previous list and adds the new price with a unique id
        priceArr: [...prevState.priceArr, { ...newPrice }]
      }));
    };

    // handlePriceSubmission = () => {
    //   const { updatePrice } = this.props;

    //   this.addPricePopup();

    //   updatePrice(priceArr);
    // };

    toggleItemEditing = (index) => {
      this.setState(prevState => ({
        priceArr: prevState.priceArr.map(priceItem => {

              // isToggleOn: !state.isToggleOn;

        })
      }));
    };

    // toggleItemEditing = index => {
    //   this.setState({
    //     items: this.state.items.map((item, itemIndex) => {
    //       if (itemIndex === index) {
    //         return {
    //           ...item,
    //           isEditing: !item.isEditing
    //         }
    //       }
    //       return item;
    //     })
    //   });
    // };


  render() {
    // const { updatePrice } = this.props;

    return (
      <div className="popup">
        <div className="popup-inner">
          <div className="price-form">
            <h2>Prices</h2>
            <div className="scroll-box">
            {this.state.priceArr.map((props) => (
              <PriceBox
                {...props}
                key={props.date}
                // toggleItemEditing={this.toggleItemEditing()}
                onChange={this.handleItemUpdate}
              />
            ))}
            </div>
            <div className="buttons-box flex-content-between">
              <button
                type="button"
                onClick={this.addPricePopup}
                className="btn add-button">Add +</button>
                {this.state.addPricePopup && (
                      <AddPriceForm
                        addPrice={this.addPrice}
                        cancelPopup={this.addPricePopup}
                      />
                    )}
              <div className="add-btns">
              <button
                type="button"
                onClick={() => this.props.closeUpdatePopup()}
                className="btn cancel-button"
              >
                Close
              </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

The list inside the component above is:

<div className="scroll-box">
            {this.state.priceArr.map((props) => (
              <PriceBox
                {...props}
                key={props.date}
                // toggleItemEditing={this.toggleItemEditing()}
                onChange={this.handleItemUpdate}
              />
            ))}
            </div>

And this is the single list item:

import React, { Component } from "react";

export default class SinglePricebox extends Component {
  state = {
    showPopup: false, //don't show popup
    todaydate: this.props.date
  };

  /* toggle and close popup edit form window */
  togglePopup = () => {
    this.setState(prevState => ({
      showPopup: !prevState.showPopup
    }));
  };


  toggleEditPriceSubmission = getPriceIndex => {
      const { toggleItemEditing, date } = this.props;

      // toggle the pop up (close)
      // this.showPopup();

      toggleItemEditing({ ...getPriceIndex, date });
      console.log("date?", date);
    };

      /* handles edit current security form submissions */
  // handleEditSecuritySubmission = editSecurity => {
  //   const { editCurrentSecurity, id } = this.props;

  //   // toggle the pop up (close)
  //   this.togglePopup();

  //   // sends the editSecurity fields (name, isin, country) + id back to
  //   // App's "this.editCurrentSecurity"
  //   editCurrentSecurity({ ...editSecurity, id });
  // };

  render() {
    return (
      <div className="pricebox">
        <article className="pricetable">
        {this.toggleEditPriceSubmission
              ? "editing" : "not editing"}
          <table>
            <tbody>
              <tr>
                <td className="date-width">{this.props.date}</td>
                <td className="price-width">{this.props.number}</td>
                <td className="editing-btn">
                  <button
                    type="button"
                    className="edit-btn"
                    onClick={this.toggleEditPriceSubmission}
                  >
                    {this.toggleEditPriceSubmission ? "Save" : "Edit"}
                  </button>
                </td>
                <td>
                  <button
                    type="button"
                    className="delete-btn">
                      X
                    </button>
                </td>
              </tr>
            </tbody>
          </table>
        </article>
      </div>
    );
  }
}

I have been struggling all afternoon to toggle the edit button in each list item. I was attempting to get the key of each list item which is the this.prop.date.

You can see my code in detail at CodeSandBox: https://codesandbox.io/s/github/kikidesignnet/caissa

2 Answers

I would create a component which will handle the list item as a form and update it as if it was SecurityForm.

 {this.state.priceArr.map((props) => {
     if(props) {
       return <PriceListForm methodToUpdate {...props} />
     }else {
       retun (
         <PriceBox
            {...props}
            key={props.date}
            // toggleItemEditing={this.toggleItemEditing()}
            onChange={this.handleItemUpdate}
          />
       );
     }
 })}

and make PriceListForm look like PriceBox but use inputs to capture new data. This way you will have two different components with less complicated logic instead of having a huge component with complex validations to check if you will display an input or not.

create a funtion named Edit to update the State

Edit = (id) => {
  this.setState({edit: !this.state.edit, id})
}

and instead of that

 <td className="country-width">{this.props.country}</td>

do something like

 <td className="country-width">{this.state.edit ? <input type="text" value={this.props.country} onChange={() => UPDATE_THE_CONTENT}/> : this.props.isin}</td>

and call the Edit function onclick of Edit Button and pass ID of that td as a param to update it. NOTE: by default THE VALUE OF EDIT STATE is false/null. you can use onChange to update that box or some other techniques like create a button along with it and use that to update it. hope this might help you

Related