ZombieChowder
ZombieChowder

Reputation: 1204

ReactJS Search and Dropdown filter synchronised

I have a search and dropdown options on my ReactJS page which I want to synchronize. Meaning that whenever you select an element from the dropdown options, the elements on the screen display only the selected filter.

The search input currently works but I am having issues with the select options. I found a working example (this one here) of a select filter but I am having issues adapting it for my solution.

I think that this function here is the main one for filtering data but I am quite unsure:

changeOption: function(type, e) {
    var val = e.target.value;
    this.props.changeOption(val, type);
  }

How can I filter data based on select options value?

Here is a JSFiddle example of my code: JS Fiddle Example

Upvotes: 1

Views: 6849

Answers (2)

Treycos
Treycos

Reputation: 7492

You will have to store the selected value in the select tag in your state, and filter your outputs depending on it :

The state :

        this.state = {
            isLoading: false,
            data: [],
            searchString: '',
            roleFilter: null
        };

Trigger function :

    changedRole = ev => {
        this.setState({ roleFilter: ev.target.value })
    }

Change event :

<select className="category-select" name="categories" onChange={this.changedRole}>

Filtering :

    {text.filter(info => roleFilter ? info.role.includes(roleFilter) : true).map(info => (
                    <div className="display">
                        <span className="role">Role: {info.role}</span><span>, Salary: {info.salary}</span>
                    </div>
                ))}

The full working code :

    class Hello extends React.Component {
    
        constructor(props) {
            super(props);
            this.state = {
                isLoading: false,
                data: [],
                searchString: '',
                roleFilter: null
            };
        }
    
        componentDidMount() {
            this.fetchData();
        }
    
        handleChange = e => {
            this.setState({ searchString: e.target.value.trim().toLowerCase() });
        }
    
        fetchData() {
            fetch("https://api.myjson.com/bins/kr5kk")
                .then(response => response.json())
                .then(json => {
                    this.setState({
                        isLoaded: true,
                        data: json
                    });
                })
                .catch(error => console.log("parsing failed", error));
        }
    
        changedRole = ev => {
            this.setState({ roleFilter: ev.target.value })
        }
    
        render() {
            var { isLoaded, data, roleFilter, searchString } = this.state;
            let text = data;
            if (searchString) {
                text = text.filter(info => info.role.toLowerCase().match(searchString));
            }
            return (
                <div>
                    <input type="text" id="searchbar" value={searchString} onChange={this.handleChange}
                        placeholder="Search by Role" name="device">
                    </input>
    
                    <select className="category-select" name="categories" onChange={this.changedRole}>
                        <option value={''}></option>
                        {text.map(info => (
                            <option value={info.role}>{info.role}</option>
                        ))}
                    </select>
                    {text.filter(info => roleFilter ? info.role.includes(roleFilter) : true).map(info => (
                        <div className="display">
                            <span className="role">Role: {info.role}</span><span>, Salary: {info.salary}</span>
                        </div>
                    ))}
                </div>
            );
        }
    }
    
    ReactDOM.render(
        <Hello name="World" />,
        document.getElementById('container')
    );
.display{
  background-color:#b6d0f9;
  margin-top:10px;
  padding-top:10px;
  padding-bottom:10px;
}
.role{
  color:red;
}
#searchbar{
  margin-right:150px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.1/umd/react-dom.production.min.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

Upvotes: 3

Tasos
Tasos

Reputation: 2036

You need to add an event listener on the select in order to catch the value when it changes. For example:

<select
  onChange={ () => this.handleSelectChange() }
  className="category-select" name="categories"
>
  {text.map(info => (
    <option value={info.role}>{info.role}</option>
  ))}
</select>

Then you need to save the current value of the select in the state of the component and filter the list according to it, the same way you do for the search.

See this. Probably duplicate.

Upvotes: 0

Related Questions