3

I have a contact list with Edit button. When it's clicked I want to make the <div> with inputs to appear. Currently, when the button is clicked, this <div> is showing for all elements in my contact list. Here's the code. I did not put here code which fetches contacts from API etc.

```

class App extends Component {

  state = {
    contacts: [],
    firstName: '',
    lastName: '',
    phoneNumber: '',
    email: '',
    editVisible: true
  };

  showEditDiv = (id) => {
    this.setState({
      editVisible: !this.state.editVisible
    })
  };

  render() {

  const visibility = this.state.editVisible ? 'unvisible' : 'visible';

    return (
        <ul>
          {this.state.contacts.map(contact => {
            return (
              <div>
                <li key={contact.id}>
                  <p>{contact.firstName} {contact.lastName}</p>
                  <p>{contact.phoneNumber}</p>
                  <p>{contact.email}</p>
                  <button onClick={() => this.removeContact(contact.id)}>Remove</button>
                  <button onClick={() => this.showEditDiv(contact.id)}>Edit</button>
                  <div key={contact.id} className={`edit-form ${visibility}`}>
                    <p>This is edit form</p>
                  </div>
                </li>
              </div>
            )
          })}
        </ul>
      </div>
    );
  }
}

export default App;
.edit-form {
  height: 100px;
  background: #a7a7a7;
}

.unvisible {
  display: none;
}

.visible {
  display: block;
}
1
  • It seems like you have an extra closing </div> tag at the end of your render method - this may be causing you layout problems Commented Aug 12, 2018 at 20:52

2 Answers 2

3

For your situation, you need to keep a separate property in your state and set the visibility for individual items. Here is a working example. If I were you I would extract contact item into its own component and get rid of those function invoking in your onClick handlers.

class App extends React.Component {
  state = {
    contacts: [
      { id: 1, firstName: "foo", lastName: "foo", email: "[email protected]" },
      { id: 2, firstName: "bar", lastName: "bar", email: "[email protected]" }
    ],
    firstName: "",
    lastName: "",
    phoneNumber: "",
    email: "",
    editVisibles: {}
  };

  showEditDiv = id => {
    this.setState(prevState => ({
      editVisibles: {
        ...prevState.editVisibles,
        [id]: !prevState.editVisibles[id]
      }
    }));
  };

  render() {
    return (
      <ul>
        {this.state.contacts.map(contact => {
          return (
            <div>
              <li key={contact.id}>
                <p>
                  {contact.firstName} {contact.lastName}
                </p>
                <p>{contact.email}</p>
                <button onClick={() => this.removeContact(contact.id)}>
                  Remove
                </button>
                <button onClick={() => this.showEditDiv(contact.id)}>
                  Edit
                </button>
                <div
                  key={contact.id}
                  className={`edit-form ${
                    !this.state.editVisibles[contact.id]
                      ? "unvisible"
                      : "visible"
                  }`}
                >
                  <p>This is edit form</p>
                </div>
              </li>
            </div>
          );
        })}
      </ul>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
.edit-form {
height: 100px;
background: #a7a7a7;
}

.unvisible {
display: none;
}

.visible {
display: block;
}
<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="root"></div>

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

5 Comments

Thanks for this! That's the working one. I've just started with deploying small app so for the start I put everything to App.js . Later I divide these parts into small components.
but is it possible if one opens and when you click on next the already open should close and the clicked one should only open. I am facing same issue..Can you help @devserkan
@midhunk, then keep only one visible state property and set its value to the item's id maybe if I understand you right.
you are right,can you show the above example in jsfiddle like tat,will be great..
You only need to change those: editVisible: undefined i removed the "s" since it is not a plural anymore. setting state: this.setState({ editVisible: id}) and div part ${this.state.editVisible !== contact.id ? "unvisible" : "visible"}
2

Instead of editVisible you could use 'contact.id`, meaning:

showEditDiv = (id) => { 
   this.setState(prevState => ({ editingContactId: prevState.editingContactId === id? null:id})) 
};

And the the div would be:

<div key={contact.id} className={contact.id === this.state.editingContactId?'edit-form visible' :'edit-form unvisible'}>
  ... 
</div>

1 Comment

Thanks! That's kinda good solution, but I have to figure out how to hide same div when Edit is clicked again.

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.