Ravenous extensions

I’ve finished the Ravenous Project and am now trying to implement some of the extensions that were suggested at the end of part 4: https://www.codecademy.com/paths/web-development/tracks/front-end-applications-with-react/modules/ravenous-part-four/projects/interacting-with-yelp-api

I’m trying to implement this one:

Allow you to search by pressing “Enter” (or “Return”) on your keyboard, as opposed to manually clicking

In SearchBar.js, I have added a new event listener on SearchBar-submit element, created a new event handler which calls the handleSearch method, and binded the new event handler to this in the constructor.

Could someone please tell me where I’m going wrong?

This is my code:

import React from 'react';
import './SearchBar.css';


class SearchBar extends React.Component {
   constructor(props) {
      super(props);
      this.state = {
         term: '',
         location: '',
         sortBy: 'best_match'
      };

      this.handleTermChange = this.handleTermChange.bind(this);
      this.handleLocationChange = this.handleLocationChange.bind(this);
      this.handleSearch = this.handleSearch.bind(this);
      this.handleKeyPress = this.handleKeyPress.bind(this);

      this.sortByOptions = {
         'Best Match': 'best_match',
         'Highest Rated': 'rating',
         'Most Reviewed': 'review_count'
      };
   }

   getSortByClass (sortByOption) {
      if (this.state.sortBy === sortByOption) {
         return 'active';
      } else {
         return '';
      }
   }
   
   
   handleSortByChange(sortByOption) {
      this.setState({ sortBy: sortByOption });
   }

   handleTermChange(event) {
      this.setState({ term: event.target.value });
   }

   handleLocationChange(event) {
      this.setState({ location: event.target.value });
   }

   handleSearch(event) {
     if (event.type === 'mousedown' || (event.type === 'keydown' && event.key === "Enter")) {
     this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy);
     event.preventDefault();
   }
}
  
  
   handleKeyPress(event) {
      if (event.key === "Enter") {
          this.handleSearch();
      }
   };
   
 
   

    renderSortByOptions() {
        return Object.keys(this.sortByOptions).map(sortByOption => {
           let sortByOptionValue = this.sortByOptions[sortByOption];
           return (<li className={this.getSortByClass(sortByOptionValue)} 
              key={sortByOptionValue} 
              onClick={this.handleSortByChange.bind(this, sortByOptionValue)}>
               {sortByOption}</li>);
        });
    }

    render() {
        return (
            <div className="SearchBar">
              <div className="SearchBar-sort-options">
                  <ul>
                  {this.renderSortByOptions()}

                  </ul>
               </div>
               <div className="SearchBar-fields">
                  <input placeholder="Search Businesses" onChange={this.handleTermChange}/>
                  <input placeholder="Where?" onChange={this.handleLocationChange}/>
               </div>
               <div className="SearchBar-submit">
                  <a onClick={this.handleSearch}
                     onKeyPress={this.handleKeyPress}>Let's Go</a>
               </div>
             </div>
        );
    }
}

export default SearchBar;

Update: I got this work by adding componentDidMount and componentWillUnmount methods. Although if there’s a better way to do it, I would be really keen to hear!

SearchBar.js

import React from 'react';
import './SearchBar.css';


class SearchBar extends React.Component {
   constructor(props) {
      super(props);
      this.state = {
         term: '',
         location: '',
         sortBy: 'best_match'
      };

      this.handleTermChange = this.handleTermChange.bind(this);
      this.handleLocationChange = this.handleLocationChange.bind(this);
      this.handleSearch = this.handleSearch.bind(this);
      this.handleKeyPress = this.handleKeyPress.bind(this);

      this.sortByOptions = {
         'Best Match': 'best_match',
         'Highest Rated': 'rating',
         'Most Reviewed': 'review_count'
      };
   }

   getSortByClass (sortByOption) {
      if (this.state.sortBy === sortByOption) {
         return 'active';
      } else {
         return '';
      }
   }
   
   handleSortByChange(sortByOption) {
      this.setState({ sortBy: sortByOption });
   }

   handleTermChange(event) {
      this.setState({ term: event.target.value });
   }

   handleLocationChange(event) {
      this.setState({ location: event.target.value });
   }

   handleSearch(event) {
     this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy);
     event.preventDefault();
   }

   handleKeyPress(event) {
      if (event.keyCode === 13) {
         this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy);
         event.preventDefault();
       }
   };

   componentDidMount() {
      document.addEventListener('keydown', this.handleKeyPress);
   }
  
   componentWillUnmount() {
      document.removeEventListener('keydown', this.handleKeyPress);
   }
   
  
    renderSortByOptions() {
        return Object.keys(this.sortByOptions).map(sortByOption => {
           let sortByOptionValue = this.sortByOptions[sortByOption];
           return (<li className={this.getSortByClass(sortByOptionValue)} 
              key={sortByOptionValue} 
              onClick={this.handleSortByChange.bind(this, sortByOptionValue)}>
               {sortByOption}</li>);
        });
    }

    render() {
        return (
            <div className="SearchBar">
              <div className="SearchBar-sort-options">
                  <ul>
                  {this.renderSortByOptions()}

                  </ul>
               </div>
               <div className="SearchBar-fields">
                  <input placeholder="Search Businesses" onChange={this.handleTermChange}/>
                  <input placeholder="Where?" onChange={this.handleLocationChange}/>
               </div>
               <div className="SearchBar-submit">
                  <a onClick={this.handleSearch}
                     onKeyPress={this.handleKeyPress}
                     >Let's Go</a>
               </div>
             </div>
        );
    }
}

export default SearchBar;

I was having a frustrating error on this and was about to ask for advice, but I just figured it out!

To address your issue, I put the onKeyPress event listeners on the two inputs instead of the submit button, since that’s where the keypress is happening. I’m not finding that I need the mount and unmount methods. Here’s my code:

handleSearch(event) {
        this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy);
        event.preventDefault();
    }

    handleKeyPress(event) {
        if (event.charCode == 13) {
        this.props.searchYelp(this.state.term, this.state.location, this.state.sortBy);
        event.preventDefault();
        }
    };

  render() {
        return (
            <div className="SearchBar">
                <div className="SearchBar-sort-options">
                    <ul>
                    {this.renderSortByOptions()}
                    </ul>
                </div>
                <div className="SearchBar-fields">
                    <input onKeyPress={this.handleKeyPress} onChange={this.handleTermChange} placeholder="Search Businesses" />
                    <input onKeyPress={this.handleKeyPress} onChange={this.handleLocationChange} placeholder="Where?" />
                </div>
                <div onClick={this.handleSearch} 
                    className="SearchBar-submit">
                    <a>Let's Go</a>
                </div>
            </div>
        )
    }
}

By the way, for anyone getting a TypeError (‘cannot display undefined property of props’ or something like that) … make sure you have your binding statement in the constructor… Took me way too long to debug that one. :smiley:

1 Like

Hey @loraxicon thanks for sharing that, it worked for me too!

1 Like