donut
donut

Reputation: 353

Controlling a checkbox in react

I'm trying to create filters in react, where i manipulate the url to return me products based on colours, cost etc

its working so if you change ?color=red to ?color=white in the url it will display different products on the page

it's also working whereby if you select the colours in my checkbox filter component it will update the url and then display the new products. i.e click on red will change the url from /sport to /sport?color=red and then returns me just the products with red

however this is my problem

if I manually change the url, I then want the checkbox checked so I tried to do this:

checked={option.text === this.getParams() ? true : false}

this does actually work but then I lose the ability to actually select and deselect the checkbox. any ideas how I can get it to do both? I guess making it a controlled and uncontrolled component simultaneously??

Upvotes: 2

Views: 3944

Answers (2)

TPHughes
TPHughes

Reputation: 1627

You should set the state of the checkbox in the component state, and then update that state when it's clicked. You can set the initial state based on the url on construct or mount.

Something like this:

constructor(props) {
  super(props);

  const isChecked = this.props.match.params.checkbox === 'true';

  this.state = {
    checkbox: isChecked
  }
}

And then in your checkbox:

<input type="checkbox" checked={this.state.checkbox} onChange={() => this._toggleCheckbox()} />

And the method to turn it on and off would be something like:

toggleCheckbox() {
  this.setState({
    checkbox: !this.state.checkbox // will toggle to the opposite of the current state
  });
}

Note that this is has not been tested but has been written based on the information you gave. The principle behind this is what you need to do. It may also be useful to set the state of the checkbox initially within componentDidMount(), rather than constructor(), but that's up to you. The onChange function of the checkbox uses ES6, but you could bind the function if you prefer or do not use ES6 with this._toggleCheckbox().bind(this)

Edit

To update the checkbox when the url is changed, rather than updating it on click, you could change the toggle method to redirect the browser, and then update the checkbox within componentWillReceiveProps. Taken from my own code with react-router you can use 'this.props.match.params' to find the url parameters. I use react-router-dom package to update the url. So for instance:

This will give you access to this.props.history.

import { withRouter } from 'react-router-dom';

toggleCheckbox() {
  // Check the current state of the checkbox and update the url to the opposite
  let toCheck = this.props.match.params.checkbox === 'true' ? 'false' : 'checked';
  this.props.history.push('/?checkbox=' + toCheck);
}

componentWillReceiveProps(newProps) {
  // Check the new url and update the checkbox if it is different from the checkbox state
  if(newProps.match.params.checkbox != this.state.checkbox) {
    this.setState({checkbox: newProps.match.params.checkbox});
  }
}

Upvotes: 1

Raghav Garg
Raghav Garg

Reputation: 3707

You need to store the filters in the state. like in your constructor you can init your state with the query parameter and then change the state upon checkbox change.

You could try something like this. You will need to change this code according to your usage, here I am assuming, this.getParams('color') will return an array of all the selected colors.

constructor state init

constructor(props) {
  super(props);

  this.state = {
    filters: this.getParams('color') // consedering, it will return array
  }
}

default check the checkbox

defaultChecked ={this.state.filters.indexOf(option.text) === -1 ? false : true}
onChange={() => this.toggleCheckbox(option.text)}

for toggling it

// if not present, then add it
// else remove it
toggleCheckbox(option) {
  if (this.state.filters.indexOf(option) === -1) {
    this.setState({
      filters: [...this.state.filters, option]
    })
  } else {
    this.setState({
      filters: this.state.filters.filter(text => text !== option)
    })
  }
}

Upvotes: 1

Related Questions