1

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

ZombieChowder
  • 1,187
  • 12
  • 36
  • 1
    1. add `onChange={this.handleChange}` to your ` –  Jan 04 '19 at 13:08
  • @ChrisG it's working now, thanks. I just wanna ask why did you change **text** with **data** for the options? – ZombieChowder Jan 04 '19 at 13:14

2 Answers2

3

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>
Treycos
  • 7,373
  • 3
  • 24
  • 47
  • Have you checked your code? After you use the dropdown, you can't access the full elements without reloading the page. – ZombieChowder Jan 04 '19 at 15:20
  • Yes, I obviously tested my code, you never said you wanted to go back to the full list. I edited my answer with an additional blank option, which solves your problem – Treycos Jan 04 '19 at 15:33
0

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.

Tasos
  • 1,880
  • 13
  • 19