2

Hello how can I handle onChange for multiple check box? The following example allows me to control the value of one checkbox.

class App extends Component {
  constructor() {
    super();
    this.state = {
      i_agree: false
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
     
  handleChange(event) {
    this.setState({i_agree: !this.state.i_agree});
  }
     
  handleSubmit(event) {
    console.log(this.state);
    event.preventDefault();
  }
     
  render() {
    return (
      <div>
        <h1>React Checkbox onChange Example - ItSolutionStuff.com</h1>
        <form onSubmit={this.handleSubmit}>
           
          <label>
            <input
              type="checkbox"
              defaultChecked={this.state.i_agree}
              onChange={this.handleChange}
            /> I Agree with this content...
          </label>
         <label>
            <input
              type="checkbox"
              defaultChecked={this.state.isChecked}
              onChange={this.handleChange}
            /> I want to control this...
          </label>
           
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

How can I set my handleChange function to handle changes for each checkbox instead of checking for one.

Reference Link

Attempt 1

class App extends Component {
      constructor() {
        super();
        this.state = {
          i_agree: false,
          isChecked: false

        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
         
      handleChange(event) {
        this.setState({
          [e.target.name]: !e.target.value
        });
      }
         
      handleSubmit(event) {
        console.log(this.state);
        event.preventDefault();
      }
         
      render() {
        return (
          <div>
            <h1>React Checkbox onChange Example - ItSolutionStuff.com</h1>
            <form onSubmit={this.handleSubmit}>
               
              <label>
                <input
                  type="checkbox"
                  defaultChecked={this.state.i_agree}
                  onChange={this.handleChange}
                  name="i_agree"
                /> I Agree with this content...
              </label>
             <label>
                <input
                  type="checkbox"
                  defaultChecked={this.state.isChecked}
                  onChange={this.handleChange}
                  name="isChecked"
                /> I want to control this...
              </label>
               
              <input type="submit" value="Submit" />
            </form>
          </div>
        );
      }
    }

I Updated the onChange handler and added name attributes in each label. But this did not work or threw any errors.

JayC
  • 2,144
  • 8
  • 42
  • 77

1 Answers1

4

I would use checked instead of defaultChecked to have a controlled checkbox input.

for handleChange you can use name and checked attributes to update checkbox state (you could also do a flip on its boolean state instead of using checked). this way you can have only one handler for all your checkboxes.

Typescript solution

import React from "react";

interface CheckboxProps {
  checked: boolean;
  label: string;
  name: string;
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}
// I abstracted Checkbox to a component but it's up to you
const Checkbox = ({ checked, onChange, label, name }: CheckboxProps) => (
  <label>
    <input
      type="checkbox"
      checked={checked} // use checked to have a controlled component
      onChange={onChange}
      name={name}
    />
    {label}
  </label>
);

interface AppState {
  iAgree: boolean;
  wantCookies: boolean;
  wishList: boolean;
}

class App extends React.Component<{}, AppState> {
  // constructor method is called implicit you can define state outside
  // for binding methods, you can declare them as arrow functions
  state = {
    iAgree: false,
    wantCookies: false,
    wishList: false
  };

  // extract name and checked properties
  handleChange = ({
    target: { name, checked }
  }: React.ChangeEvent<HTMLInputElement>) =>
    this.setState({ [name]: checked } as Pick<AppState, keyof AppState>);

  handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    console.log(this.state);
    event.preventDefault();
  };

  render() {
    const { iAgree, wantCookies, wishList } = this.state;
    return (
      <div>
        <h1>React Checkbox onChange Example - ItSolutionStuff.com</h1>
        <form onSubmit={this.handleSubmit}>
          <Checkbox
            onChange={this.handleChange}
            name={"iAgree"}
            checked={iAgree}
            label={"I agree with terms"}
          />
          <Checkbox
            onChange={this.handleChange}
            name={"wantCookies"}
            checked={wantCookies}
            label={"I want more cookies"}
          />
          <Checkbox
            onChange={this.handleChange}
            name={"wishList"}
            checked={wishList}
            label={"Put Me on wishlist"}
          />
          <br />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default App;

Javascript solution

import React from "react";

// I abstracted Checkbox to a component but it's up to you
const Checkbox = ({ checked, onChange, label, name }) => (
  <label>
    <input
      type="checkbox"
      checked={checked} // use checked to have a controlled component
      onChange={onChange}
      name={name}
    /> { label }
  </label>
)

class App extends React.Component {
    // constructor method is called implicit you can define state outside
    // for binding methods, you can declare them as arrow functions
    state = {
      iAgree: false,
      wantCookies: false,
      wishList: false,
    };

  // extract name and checked properties
  handleChange = ({target: { name, checked }}) => this.setState({[name]: checked});
  
  handleSubmit= (event) => {
    console.log(this.state);
    event.preventDefault();
  }
     
  render() {
    const { iAgree, wantCookies, wishList } = this.state
    return (
      <div>
        <h1>React Checkbox onChange Example - ItSolutionStuff.com</h1>
        <form onSubmit={this.handleSubmit}>
          <Checkbox onChange={this.handleChange} name={'iAgree'} checked={iAgree} label={'I agree with terms'} />
          <Checkbox onChange={this.handleChange} name={'wantCookies'} checked={wantCookies} label={'I want more cookies'} />
          <Checkbox onChange={this.handleChange} name={'wishList'} checked={wishList} label={'Put Me on wishlist'} />
          <br/>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default  App

fwiw I removed the constructor since it's not necessary. You can keep it though, it's only a cleaner way to declare your classes.

sandbox with implementation TS: https://codesandbox.io/s/so-multi-checkboxes-ts-qz20m

sandbox with implementation JS: https://stackblitz.com/edit/so-multi-checkboxes?file=src/App.js

buzatto
  • 9,704
  • 5
  • 24
  • 33
  • This is what I am looking for, however handleChange function you have here is not working for me. – JayC Jan 06 '21 at 03:40
  • 1
    added a sandbox with code implementation to help you out. you can check it out to find if there's any difference. – buzatto Jan 06 '21 at 03:52
  • I appreciate your help! This is it! – JayC Jan 06 '21 at 03:55
  • When I tried to add the const CheckBox I am seeing this syntax error: var checked: any Binding element 'checked' implicitly has an 'any' type.ts(7031) for --> ({ checked, onChange, label, name } – JayC Jan 06 '21 at 04:01
  • this is related to typescript, I didn't notice you were using `ts` at your code. you need to add an interface to declare the props type. here you have a similar issue that might solve it https://stackoverflow.com/questions/55370851/how-to-fix-binding-element-children-implicitly-has-an-any-type-ts7031 – buzatto Jan 06 '21 at 04:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/226906/discussion-between-jesse-and-buzatto). – JayC Jan 06 '21 at 04:14
  • added ts solution as well along with js one. – buzatto Jan 06 '21 at 12:50