2

In my react application a user enters a keyword and gets a list of results. I am trying to implement filters on these results. Below is the screenshot of filters. enter image description here

Here is my state

class SearchResultsPage  extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            results: this.props.location.state.data.results,
            keyword: this.props.location.state.data.keyword,
            pageOfItems: [],
            cities: {
                'New York City (NYC)': false,
                'Delhi': false,
                'Bangkok': false,
                'Paris': false,
                'Mexico City': false
            },
            topics: {
                'Environment': false,
                'Crime': false,
                'Politics': false,
                'Social Unrest': false,
                'Infrastructure': false
            },
            languages: {
                'Hindi': false,
                'English': false,
                'Thai': false,
                'French': false,
                'Spanish': false
            }
        };
        this.onChangePage = this.onChangePage.bind(this);
        this.onCityChange = this.onCityChange.bind(this);
    }

What I am trying to do is, whenever a checkbox is checked or unchecked I am setting the corresponding checkbox to true/false. Based on this boolean value of each checkbox I am filtering out the results and then rendering it on the UI. I am able to filter the results when a checkbox is clicked, but I am unable to show all the results back when the checkbox is unchecked. This is how I am handling when checkbox changes.

onCityChange(e) {
        const val = e.target.checked;
        const name = e.target.name;
        let updatedCities = Object.assign({},this.state.cities,{[name]: val});
        this.setState({
            cities: updatedCities,
        },function () {
            const filteredCities = [];
            for (let key in this.state.cities) {
                if (this.state.cities[key] === true) {
                    filteredCities.push(key)
                }
            }
            const filteredResults = [];
            this.state.results.forEach((result) => {
                for (let i = 0; i < filteredCities.length; i++) {
                    if (result.city === filteredCities[i] && result.city != null) {
                        filteredResults.push(result)
                    }
                }
            })
            console.log(filteredResults.length)
            if (filteredResults.length > 0) {
                this.setState({
                    results: filteredResults
                })
            }
        })
    }

I know I am not correctly handling the state, what can I do in this situation. For better reference, here is the complete Search Result code.

import React from 'react';
import NavigationBar from './NavigationBar';
import SearchPageResultsStyle from "../assets/css/SearchResultsPage.css"
import Pagination from './Pagination';

class SearchResultsPage  extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            results: this.props.location.state.data.results,
            keyword: this.props.location.state.data.keyword,
            pageOfItems: [],
            cities: {
                'New York City (NYC)': false,
                'Delhi': false,
                'Bangkok': false,
                'Paris': false,
                'Mexico City': false
            },
            topics: {
                'Environment': false,
                'Crime': false,
                'Politics': false,
                'Social Unrest': false,
                'Infrastructure': false
            },
            languages: {
                'Hindi': false,
                'English': false,
                'Thai': false,
                'French': false,
                'Spanish': false
            }
        };
        this.onChangePage = this.onChangePage.bind(this);
        this.onCityChange = this.onCityChange.bind(this);
    }

    onChangePage(pageOfItems) {
        // update local state with new page of items
        this.setState({pageOfItems});
    }

    // setting each city in cities object (city chechboxes which are clicked on UI) to true
    onCityChange(e) {
        const val = e.target.checked;
        const name = e.target.name;
        let updatedCities = Object.assign({},this.state.cities,{[name]: val});
        this.setState({
            cities: updatedCities,
        },function () {
            const filteredCities = [];
            for (let key in this.state.cities) {
                if (this.state.cities[key] === true) {
                    filteredCities.push(key)
                }
            }
            const filteredResults = [];
            this.state.results.forEach((result) => {
                for (let i = 0; i < filteredCities.length; i++) {
                    if (result.city === filteredCities[i] && result.city != null) {
                        filteredResults.push(result)
                    }
                }
            })
            console.log(filteredResults.length)
            if (filteredResults.length > 0) {
                this.setState({
                    results: filteredResults
                })
            }
        })
    }

    // rendering checkboxes for topics
    renderCityFilter() {
        const cities = ['New York City (NYC)','Delhi','Bangkok','Paris','Mexico City']
        return cities.map((city,i) => {
            return (
                <div key={i} className={'city-filters'}>
                    <input
                        type="checkbox"
                        name={city}
                        onChange={this.onCityChange}
                        value={this.state.cities[city]}/>&nbsp;&nbsp;
                    <label key={i} style={{fontSize:12}}>
                        {city}
                    </label>
                </div>

            )
        })
    }

    // rendering checkboxes for topics
    renderTopicFilter() {
        const topics = ['Environment','Crime','Politics','Social Unrest','Infrastructure']
        return topics.map((topic,i) => {
            return (
                <div key={i}>
                    <input
                        type="checkbox"
                        name={topic}
                        onChange={this.onCityChange}
                        value={this.state.topics[topic]}/>&nbsp;&nbsp;
                    <label key={i} style={{fontSize:12}}>
                        {topic}
                    </label>
                </div>

            )
        })
    }

    // rendering checkboxes for languages
    renderLanguageFilter() {
        const languages = ['Hindi','English','Thai','French','Spanish']
        return languages.map((language,i) => {
            return (
                <div key={i}>
                    <input
                        type="checkbox"
                        name={language}
                        onChange={this.onCityChange}
                        value={this.state.languages[language]}/>&nbsp;&nbsp;
                    <label key={i} style={{fontSize:12}}>
                        {language}
                    </label>
                </div>

            )
        })
    }

    render() {

        const renderItems = this.state.pageOfItems.map((item, index) => {
            return (
                <div key={index}>
                    <h3 style={{color: '#1a0dab'}} key={index}>{item.text}</h3>
                    <a href={'https://google.com'} key={index}>{item.tweetUrl}</a>
                    <br/>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>topic: </span>{item.topic}</p>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>city: </span>{item.city}</p>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>lang: </span>{item.lang}</p>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>Hashtags: </span></p>
                    <hr/>
                </div>
            )
        });

        return (
            <div>
                <NavigationBar/>
                <h4 style={{textAlign:'center', color:'#1a0dab'}}>Showing search results for <span style={{fontWeight:'bold', fontStyle:'Italic'}}>'{this.state.keyword}'</span></h4>
                <hr/>
                <div className={'wrap'} style={SearchPageResultsStyle}>
                    <div className={'fleft'}>
                        <h4>City</h4>
                        {this.renderCityFilter()}
                        <hr/>
                        <h4>Topics</h4>
                        {this.renderTopicFilter()}
                        <hr/>
                        <h4>Language</h4>
                        {this.renderLanguageFilter()}
                        <hr/>
                    </div>
                    <div className={'fcenter'}>
                        {renderItems}
                        <Pagination items={this.state.results} onChangePage={this.onChangePage}/>
                    </div>
                    <div className={'fright'}/>
                </div>
            </div>
        )
    }
}

export default SearchResultsPage;

2
  • How come all of your inputs have the same onChange function? Commented Jan 14, 2019 at 22:19
  • @pengcheng95 I will write specific functions for all those inputs later, for now, I am testing on just CIty filters and facing the above mentioned issue. Commented Jan 15, 2019 at 1:23

1 Answer 1

2

Try implementing filtered state separately instead of combining with results, take a look at my solution:

import React from 'react';
import NavigationBar from './NavigationBar';
import SearchPageResultsStyle from "../assets/css/SearchResultsPage.css"
import Pagination from './Pagination';

class SearchResultsPage  extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            results: this.props.location.state.data.results,
            isFiltered: false, //NEW STATE
            filteredResults: [], //NEW STATE
            keyword: this.props.location.state.data.keyword,
            pageOfItems: [],
            cities: {
                'New York City (NYC)': false,
                'Delhi': false,
                'Bangkok': false,
                'Paris': false,
                'Mexico City': false
            },
            topics: {
                'Environment': false,
                'Crime': false,
                'Politics': false,
                'Social Unrest': false,
                'Infrastructure': false
            },
            languages: {
                'Hindi': false,
                'English': false,
                'Thai': false,
                'French': false,
                'Spanish': false
            }
        };
        this.onChangePage = this.onChangePage.bind(this);
        this.onCityChange = this.onCityChange.bind(this);
    }

    onChangePage(pageOfItems) {
        // update local state with new page of items
        this.setState({pageOfItems});
    }

    // setting each city in cities object (city chechboxes which are clicked on UI) to true
    onCityChange(e) {
        const val = e.target.checked;
        const name = e.target.name;
        let updatedCities = Object.assign({},this.state.cities,{[name]: val});
        this.setState({
            cities: updatedCities,
        },function () {
            const filteredCities = [];
            for (let key in this.state.cities) {
                if (this.state.cities[key] === true) {
                    filteredCities.push(key)
                }
            }
            // CHECK IF SHOULD FILTER
            if (filteredCities.length > 0) {
                const filteredResults = [];
                this.state.results.forEach((result) => {
                    for (let i = 0; i < filteredCities.length; i++) {
                        if (result.city === filteredCities[i] && result.city != null) {
                            filteredResults.push(result)
                        }
                    }
                })
                console.log(filteredResults.length)
                if (filteredResults.length > 0) {
                    this.setState({
                        isFiltered: true,
                        filteredResults: filteredResults
                    })
                }
            } else {
                this.setState({
                    isFiltered: false,
                    filteredResults: []
                })
            }
        })
    }

    // rendering checkboxes for topics
    renderCityFilter() {
        const cities = ['New York City (NYC)','Delhi','Bangkok','Paris','Mexico City']
        return cities.map((city,i) => {
            return (
                <div key={i} className={'city-filters'}>
                    <input
                        type="checkbox"
                        name={city}
                        onChange={this.onCityChange}
                        value={this.state.cities[city]}/>&nbsp;&nbsp;
                    <label key={i} style={{fontSize:12}}>
                        {city}
                    </label>
                </div>

            )
        })
    }

    // rendering checkboxes for topics
    renderTopicFilter() {
        const topics = ['Environment','Crime','Politics','Social Unrest','Infrastructure']
        return topics.map((topic,i) => {
            return (
                <div key={i}>
                    <input
                        type="checkbox"
                        name={topic}
                        onChange={this.onCityChange}
                        value={this.state.topics[topic]}/>&nbsp;&nbsp;
                    <label key={i} style={{fontSize:12}}>
                        {topic}
                    </label>
                </div>

            )
        })
    }

    // rendering checkboxes for languages
    renderLanguageFilter() {
        const languages = ['Hindi','English','Thai','French','Spanish']
        return languages.map((language,i) => {
            return (
                <div key={i}>
                    <input
                        type="checkbox"
                        name={language}
                        onChange={this.onCityChange}
                        value={this.state.languages[language]}/>&nbsp;&nbsp;
                    <label key={i} style={{fontSize:12}}>
                        {language}
                    </label>
                </div>

            )
        })
    }

    render() {

        const renderItems = this.state.pageOfItems.map((item, index) => {
            return (
                <div key={index}>
                    <h3 style={{color: '#1a0dab'}} key={index}>{item.text}</h3>
                    <a href={'https://google.com'} key={index}>{item.tweetUrl}</a>
                    <br/>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>topic: </span>{item.topic}</p>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>city: </span>{item.city}</p>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>lang: </span>{item.lang}</p>
                    <p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>Hashtags: </span></p>
                    <hr/>
                </div>
            )
        });

        return (
            <div>
                <NavigationBar/>
                <h4 style={{textAlign:'center', color:'#1a0dab'}}>Showing search results for <span style={{fontWeight:'bold', fontStyle:'Italic'}}>'{this.state.keyword}'</span></h4>
                <hr/>
                <div className={'wrap'} style={SearchPageResultsStyle}>
                    <div className={'fleft'}>
                        <h4>City</h4>
                        {this.renderCityFilter()}
                        <hr/>
                        <h4>Topics</h4>
                        {this.renderTopicFilter()}
                        <hr/>
                        <h4>Language</h4>
                        {this.renderLanguageFilter()}
                        <hr/>
                    </div>
                    <div className={'fcenter'}>
                        {renderItems}
                        {//CHECK SHOULD RENDER RESULTS OR FILTEREDRESULTS}
                        <Pagination items={this.state.isFiltered ? this.state.filteredResults : this.state.results} onChangePage={this.onChangePage}/>
                    </div>
                    <div className={'fright'}/>
                </div>
            </div>
        )
    }
}

export default SearchResultsPage;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.