Reputation: 353
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
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)
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
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