Tutorial - Create a React.js Auto-complete Search Box With Material-UI in < 100 Lines of Code - Part II

June 20, 2016

In part I of this series, I demonstrated to developers how to write the first part of a React.js auto-complete search box for Youtube that piggy-backs on top of Material-UI.

This component is titled MaterialUIAutocomplete (for lack of a better name!).

Take a moment to review part I of this series it if you haven’t.

As I mentioned in part I, the auto-complete search box is designed for apps that need to search Youtube. Therefore, the component is of limited use; however, it’s simple enough to demo and explain a core concept: how to reuse other libraries in order to build something new.

In this second post, I’m going to demonstrate the last part: how the component retrieves video search results from Youtube’s API after a user selects a suggested term, and a few details regarding the public-facing API for the component.

As advertised, the entire source code for this component is less than 100 lines of code.


What the Component Currently Provides

Right now, the auto-complete search box provides suggested search terms as a user types (which are retrieved from Youtube in real-time).

It currently looks like this:


Dummy component snapshot 2 - successfully populating dropdown list

To complete the component, logic needs to be added so that when a user selects a suggested search term, video search results are retrieved.

In order to do that, the component will use Material-UI’s onNewRequest() function that is part of the API for the auto-complete component.

Here’s the documentation for the onNewRequest() function.


Auto-complete onUpdateInput documentation

When a User Selects a Search Term

When a user selects a search term, the component needs to take the selected term and pass it as a query to Youtube’s API.

On line 11 of the code below, I pass a function to the onNewRequest prop. For now, this function simply displays an alert.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
  ...
  onNewRequest(searchTerm) {
    alert('test123!');
  }

  render() {
    return <MuiThemeProvider muiTheme={getMuiTheme()}>
      <AutoComplete
        dataSource    ={this.state.dataSource}
        onUpdateInput ={this.onUpdateInput}
        onNewRequest  ={this.onNewRequest} />
      </MuiThemeProvider>
  }
  ...


When a user selects a term and hits enter, the component simply displays an alert.


Show alert on search term click

This works great when a user hits the enter key. But when a user clicks or taps a term, the search term doesn’t get selected. This needs to be fixed.


React-Tap-Event-Plugin

Mobile browsers have a built-in 300ms delay between a user tapping an item and a mobile browser considering it a click.

This delay was implemented because many sites are still not mobile-optimized, and users double-tap on items to zoom in and expand them. Therefore, mobile browsers need to determine if a user intended a double-tap, hence the delay.

React hasn’t decided how to effectively deal with this, and its built-in onClick attribute falls prey to this delay.

Furthermore, Material-UI components actually rely on a module called react-tap-event-plugin, so you need to apply it in order to get things to work correctly.

After the addition of the code below (lines 6 and 8), tapping or clicking a search term will work.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  import React, { Component } from 'react'
  import { AutoComplete }     from 'material-ui';
  import JSONP                from 'jsonp';
  import getMuiTheme          from 'material-ui/styles/getMuiTheme';
  import MuiThemeProvider     from 'material-ui/styles/MuiThemeProvider';
  import injectTapEventPlugin from 'react-tap-event-plugin';

  injectTapEventPlugin();

  const googleAutoSuggestURL = '//suggestqueries.google.com/complete/search?client=youtube&ds=yt&q=';

  class MaterialUIAutocomplete extends Component {
    constructor(props) {
      super(props);
      this.onUpdateInput  = this.onUpdateInput.bind(this);
      ....


The Youtube-Finder NPM Module

Now that the component is responding to taps, clicks, and keyboard presses, the component has to communicate with Youtube.

Of course, I could write this by hand. But why bother when there is probably a pre-made npm module that already does the job?

Indeed, there is an npm module titled Youtube-Finder which makes it easy to connect to the Youtube API.

I import this module with the other imports on line 7.


1
2
3
4
5
6
7
8
  import React, { Component } from 'react'
  import { AutoComplete }     from 'material-ui';
  import JSONP                from 'jsonp';
  import getMuiTheme          from 'material-ui/styles/getMuiTheme';
  import MuiThemeProvider     from 'material-ui/styles/MuiThemeProvider';
  import injectTapEventPlugin from 'react-tap-event-plugin';
  import YoutubeFinder        from 'youtube-finder';
  ...


Youtube-Finder requires that you instantiate it by providing the API key that you registered with Youtube. A registered API key will be required for any developer that makes use of this component and requires search results to be fetched.

In the constructor on line 6, I call YoutubeFinder.createClient and pass in the apiKey which is passed in as a prop.


1
2
3
4
5
6
7
8
9
10
11
12
 ...
 constructor(props) {
    super(props);
    this.onUpdateInput  = this.onUpdateInput.bind(this);
    this.onNewRequest   = this.onNewRequest.bind(this);
    this.YoutubeClient  = YoutubeFinder.createClient({ key: this.props.apiKey });
    this.state = {
      dataSource : [],
      inputValue : ''
    }
  }
  ...


Let’s step back for a moment, and look at the component from the vantage of a developer who is trying to consume it.

Another developer using the MaterialUIAutocomplete component would need to provide an apiKey and callback in the following way.


1
2
3
4
5
6
7
8
9
10
import MaterialUIAutocomplete from 'material-ui-autocomplete';

yourCallback(searchResults) {
  console.log('searchResults are: ', searchResults);
},

<MaterialUIAutocomplete
  apiKey   ='AIzaSyAtSE-0lZOKunNlkHt8wDJk9w4GjFL9Fu4',
  callback ={this.yourCallback}
/>


As previously stated, the apiKey is required by Youtube if you want to communicate with its API.

The callback is required because once search results are retrieved, they need to be passed somewhere so the developer can manipulate and display them.


Retrieving Video Search Results

Now that’s in place, it’s time to add the logic that will fetch actual results when a user selects a suggested term. Here’s the ehanced code to the onNewRequest() function.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  ...
  onNewRequest(searchTerm) {
    const
      self   = this,
      params = {
        part        : 'id,snippet',
        type        : 'video',
        q           : this.state.inputValue,
        maxResults  : '50'
      }

    this.YoutubeClient.search(params, function(error,results) {
      if(error) return console.log(error);

      self.props.callback(results.items,searchTerm);

      self.setState({
        dataSource : [],
        inputValue : ''
      });
    });
  }
  ...


On line 5, I set up params required by Youtube. The key “q” is the suggested term selected by the user.

On line 12, the API call to Youtube gets made with params passed in as an argument. A callback gets executed when results come back.

When the results are returned, the results get passed to the callback provided by the developer (line 15).


Video search results provided in Chrome console

The developer can then manipulate and display the results in any way.

For example, in the snapshot below I simply display search results in a view for my app VideoYak.


Video search results displayed in web page

Packaging, Publishing, and Sharing

You can design the API of your component in many ways, and you can make as many things configurable as you want.

Ultimately, the documentation you provide will be critical and I give some pointers in my guide Publish Your React Component.

After you’ve completed any component that you’ve developed, the last step is to package it and publish it on NPM. There are great tools to help you do this, and I walk you through them in my guide.

Seriously, sharing is one of the best parts of software development. Don’t miss out!


Conclusion

I hope that you gained some new insight by reading this blog series.

As a Developer who has worked on the Web for a while, I believe that the “thinking in components” approach to developing and architecting large-scale web apps holds a lot of promise.

In this series, the main point I’m trying to convey to other Front-End Engineers is that building advanced UI functionality doesn’t always require doing everything from scratch.

Developing UI components is akin to using lego blocks in order to build functionality nobody has created before.

Furthermore, you don’t always have to build apps and full-fledged prototypes to gain practice and expand your portfolio. Creating and sharing a cool component that others can use is a great way to get your name out there.

Happy coding! And remember…take a break and get some fresh air.


How to Instantly Publish Your Own React Component

Publish Your React Component book cover

Learn how to create and publish your own UI components on NPM, and share your code with the world.

Start learning the insanely popular React.js from Facebook now. If you're a seasoned or new developer, open-sourcing your own component is a great way to get recognized.

START PUBLISHING