1

I am trying to learn how to use forms in React.

It is a form with options to select.

On an onclick event, the clicked span tag should change the background color (just to show it was clicked), I am able to achieve this for a single tag but for multiple tags if I click on a single span bg color of both the tags gets changed.

Code:

import React from "react";

class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
  userClick: true
};
this.handleChange = this.handleChange.bind(this);
this.handleChange1 = this.handleChange1.bind(this);
}

 handleChange(e) {
  alert(`You selected... ${e.target.textContent}`);
  this.setState({
  userClick: !this.state.userClick
  });
}

handleChange1(e) {
  alert(`You selected... ${e.target.textContent}`);
 this.setState({
  userClick: !this.state.userClick
  });
}

render() {
return (
  <div className="form-mode">
    <h6>Services:</h6>
    <div className="spans">
      <span
        onClick={this.handleChange}
        className={this.state.userClick ? "youClicked" : "unClicked"}
      >
        {" "}
        inPerson{" "}
      </span>
      <span onClick={this.handleChange1} className={this.state.userClick ? "youClicked" : "unClicked"}> Virtual</span>
    </div>
  </div>
  );
}
}

 export default MyForm;
1
  • 1
    It is working fine. it is just that both the listener are changing the same state (which is not recommended). Commented Mar 3, 2020 at 9:07

1 Answer 1

1

Both on click functions are changing the same state variable, userClick. If you want the 2 spans to act independently, you'll need two state variables, e.g:

handleChange(e) {
  alert(`You selected... ${e.target.textContent}`);
  this.setState({
     firstSpanClick: !this.state.firstSpanClick
  });
}

handleChange1(e) {
  alert(`You selected... ${e.target.textContent}`);
  this.setState({
     secondSpanClick: !this.state.secondSpanClick
  });
}

<span onClick={this.handleChange1} className={this.state.firstSpanClick ? "youClicked" : "unClicked"}> Virtual</span>

<span onClick={this.handleChange2} className={this.state.secondSpanClick ? "youClicked" : "unClicked"}> Virtual</span>

A cleaner way of achieving the same outcome would be to name the spans and have one handleChange.

//Each toggle variable doesn't need to be initialised, this is just for demonstration.

this.state = {
   spanOne: false,
   spanTwo: false
}

handleChange = (e) => {
        let name = e.target.getAttribute('name');
        this.setState({
            [name]: !this.state[name]
        });
    };

<span onClick={this.handleChange} name={'spanOne'} className={this.state.spanOne ? "youClicked" : "unClicked"}> Virtual</span>

<span onClick={this.handleChange} name={'spanTwo'} className={this.state.spanTwo ? "youClicked" : "unClicked"}> Virtual</span>
Sign up to request clarification or add additional context in comments.

5 Comments

thanks a lot,it worked. I have a follow up question to it, say if there are multiple options(span tags) , do I need to follow the same practice for each and every span tag or is there something equivalent to getElementsByTagName and running a loop to make the change on which ever is clicked?
Please see the bottom example, you can just add a different name to the span and use the same handleChange.
I saw that after making the comment. Thanks.
If it's a form, i suggest you to use the existing form html tag with input with type checkbox. You could then use the css selector input:checked to add the style you want without defining a state and a name attribute for each span.
@amcquaid the second way is not working, there is no toggle effect on onClick.

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.