ShowstopperCode1
ShowstopperCode1

Reputation: 130

How to show message when filtered list is empty in React

I am working on a project in which I am trying to show a div of content that says No results found for if the user types letters in the search input that do not match any filter in the list. I've tried using this similar solution as reference: React: How to show message when result is zero in react, but without success.

Here is a snippet of my code and one solution (of many) I have tried so far:

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      searchQuery: ""
    };
  }

  handleSearchQuery = event => {
    this.setState({ searchQuery: event.target.value });
  };

  resetInputField = () => {
    this.setState({ searchQuery: "" });
  };

  render() {
    const { subContent, type, options, label } = this.props;
    const { searchQuery } = this.state;
    return (
      <div
        style={{
          display: "grid",
          alignItems: "center",
          width: "100%",
          margin: "0 0 24px 0",
          fontSize: "14px"
        }}
      >
        <div style={sx.rangeInputContainer}>
          <input
            style={sx.rangeInputLong}
            type="text"
            placeholder={placeholderText}
            onChange={this.handleSearchQuery}
            value={searchQuery}
          />
        </div>
        <div>
          {options
            .filter(
              option =>
                option.label
                  .toLowerCase()
                  .includes(searchQuery.toLowerCase()) || !searchQuery
            )
            .map((option, index) => {
              return option.label.length !== 0 ? (
                <div key={index} style={sx.filterOption}>
                  <SquareCheckbox
                    type="checkbox"
                    id={"multiSelectCheckbox-" + option.label}
                  />
                  <label
                    style={{ color: "#FFF" }}
                    htmlFor={"multiSelectCheckbox-" + option.label}
                  >
                    {option.label}
                  </label>
                </div>
              ) : (
                <div
                  key={index}
                  style={{
                    display: "flex",
                    alignItems: "center",
                    marginTop: "16px"
                  }}
                >
                  <img
                    style={{ width: "20px", cursor: "pointer" }}
                    src={resetIconSVG}
                    onClick={this.resetInputField}
                  />
                  <div style={{ marginLeft: "16px" }}>
                    No results found for {searchQuery}
                  </div>
                </div>
              );
            })}
        </div>
      </div>
    );
  }
}

Here's a snippet of options, which is in my parent component:

this.state = {
        filters: [


            {
                label: 'Materials',
                type: FILTER_TYPE.MULTI_SELECT,
                expandedHandle: ()=> {  
                this.handleExpandedToggle('Materials'); },
                options:materials,
                expanded:false,
            },
            {
                label: 'Status',
                type: FILTER_TYPE.SELECT,
                expandedHandle: ()=> {  this.handleExpandedToggle('Status'); 
             },
                options: status,
                expanded:false,
            },


        ],
    };

And the dummy .json data I am using:

export const materials = [
{ value: 'brass', label: 'brass' },
{ value: 'chrome', label: 'chrome' },
{ value: 'ceramic', label: 'ceramic' },
{ value: 'glass', label: 'glass' },
{ value: 'concrete', label: 'concrete' },

];

export const status = [
{ value: 'Show All', label: 'Show All' },
{ value: 'Enabled Only', label: 'Enabled Only' },

];

Upvotes: 0

Views: 5225

Answers (2)

Dmitriy
Dmitriy

Reputation: 1241

Seems like your using a ternary operator inside of a return on your filter method. I would put the filter into a variable

const filteredOptions = options.filter(option => option.label.toLowerCase().includes(searchQuery.toLowerCase()) || !searchQuery).map((option, index) => {
  return option.label.length !== 0 ? <div key={index} style={sx.filterOption}>
    <SquareCheckbox type='checkbox' id={'multiSelectCheckbox-' + option.label} />
    <label style={{ color: '#FFF' }} htmlFor={'multiSelectCheckbox-' + option.label}> {option.label} </label>
  </div> })

and in your render use the ternary to check the length of the array

render {
 return (
  {filteredOptions.length > 0 ? filteredOptions : <div style = {{ marginLeft: '16px' }}>No results found for { searchQuery }</div>}
  )
}

Upvotes: 2

Tu Nguyen
Tu Nguyen

Reputation: 10179

I've made an assumption about your options data, hopefully this helps (I simplified the codes)

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      searchQuery: ''
    };
  }
  handleSearchQuery = event => {
    this.setState({ searchQuery: event.target.value });
  };
  resetInputField = () => {
    this.setState({ searchQuery: '' });
  };
  render() {
    const { searchQuery } = this.state;
    const options = [
      { label: 'react' },
      { label: 'angular' },
      { label: 'vue' }
    ];
    const filteredOptions = options.filter(
      option =>
        option.label.toLowerCase().includes(searchQuery.toLowerCase()) ||
        !searchQuery
    );
    return (
      <div>
        <div>
          <input
            type="text"
            onChange={this.handleSearchQuery}
            value={searchQuery}
          />
        </div>
        <div>
          {filteredOptions.length > 0 ? (
            filteredOptions.map((option, index) => {
              return <div key={index}>{option.label}</div>;
            })
          ) : (
            <div>
              No results found for {searchQuery}
            </div>
          )}
        </div>
      </div>
    );
  }
}
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

Upvotes: 4

Related Questions