ReactJS is a fantastic platform for constructing responsive interface components, and has emerged as one of the premier frameworks when it comes to building user interfaces. The growing list of React contributions from the open source community is quite extraordinary.

Let’s build something cool using React


In this tutorial we’ll step through how to create the autocomplete control that’s previewed above… This component integrates Twitter’s Typeahead.js control with the ReactJS stack.

References

GitHub Repo:React-Twitter-Typeahead
Demo Site: Azure Site with working demos

ReactJS Setup

Lets first clone the repo and install the necessary dependencies

git clone https://github.com/erikschlegel/React-Twitter-Typeahead.git
cd React-Twitter-Typeahead
npm install
npm run build

At this point, the repo and all required packages have been installed which also includes all bower dependencies. The magic in the ‘npm run build’ command is the grunt build task from Grunt.js. Also worth noting that React components are written in a templating language called JSX. We’ll use grunt-browserify to convert JSX syntax to javascript code that jives with React.

grunt.registerTask('build', ['bower', 'browserify:lib']);

Validate everything works as expected by opening up a browser and hitting %CWD%/example/index.html . You should see the demo’s fully functional.

Lets start coding…
Let’s perform our work in the example folder. Create a html file called myComponent.html, and copy and paste the text below.

<!DOCTYPE html>
<html>
    <head>
        <title>React Typeahead Example</title>
        <link rel="stylesheet" type="text/css" href="../lib/css/typeahead.css" />
        <link rel="stylesheet" type="text/css" href="typeahead-custom-template.css" />
    </head>
    <body>
         <h3>My styled autosuggest</h3>
         <div id="#typeaheadDiv">
        </div>
    </body>
    <script src="../vendor/jquery/jquery.js"></script>
    <script src="../vendor/typeahead.js/typeahead.bundle.js"></script>
    <script src="./dist/example.js"></script>
</html>

React will bind the component to the div tag based on the id. This control is powered by Twitter’s typeahead.js, which has dependencies on jquery included in your markup.

Lets implement the react side of things. Create a file in the example folder called example.js. In this example we’re making a JSONP remote call, pre-process the payload and use a handlebar template to dress up the results on the typeahead.js control.

'use strict';

var React = require('react');
var ReactTypeahead = require('./lib/js/react-typeahead');
var Handlebars = require('handlebars');

var handlerbarTemplate = '<div class="tt-custom-row"> ' + 
                                   '     <span class="tt-custom-cell tt-custom-thumbnail">' + 
                                   '         <img src="{{thumbnail}}" />' + 
                                   '     </span>' + 
                                   '     <span class="tt-custom-cell">' +
                                   '           <h3>{{value}}</h3>' + 
                                   '           <p>{{description}}</p>' + 
                                   '     </span>' +
                                   ' </div>';

This includes the core react library imports, and the handlebar custom template used for each row in the dropdown result list.

Configuring the remote call
Bloodhound is typeahead.js’s powerful suggestion engine, which allows you to transform the returned response prior to typeahead.js processing(var responseTransformation). In the example below we’re extracting the data points from the response that are relevant for rendering. The URL call can be configured in the ‘remote’ object of the bloodhound config. All other available options are listed in Twitter’s API docs.

Feel free to plug-in your own restful endpoint, and override the response transformer.

var responseTransformation = function(rsp){
      var initRsp = rsp.items, maxCharacterTitleLgth = 29, maxDescLength = 80;
      var finalResult = [];

      initRsp.map(function(item){
          var title = item.volumeInfo.title;
          finalResult.push({value: title.length>maxCharacterTitleLgth?title.substring(0, maxCharacterTitleLgth):title,
                            thumbnail: item.volumeInfo.imageLinks.thumbnail,
                            id: item.id,
                            description:(item.volumeInfo.description)?item.volumeInfo.description.substring(0, maxDescLength):''});
      });

      return finalResult;
};

var bloodhoundRemoteConfig = {
  remote: {
    url: 'https://www.googleapis.com/books/v1/volumes?q=%QUERY',
    wildcard: '%QUERY',/*typeahead.js will replace the specified wildcard with the inputted value in the GET call*/
    transform: responseTransformation
  }
};

Adding some style
You can customize the presentation of the remote dataset by overriding the dataset config. All available options are listed here. This project comes packaged with handlebars, but you’re free to use your template library of choice.

var datasetConfig = {
  name: 'books-to-buy',
  display: 'value',
  limit: 8,
  templates: {
    header: header,
    pending: '<div style="padding-left:5px;">Processing...</div>',
    empty: '<div>unable to find any books that matched your query</div>',
    suggestion: Handlebars.compile(handlerbarTemplate)
  }
};

Stand up our React component

React.render(
    <ReactTypeahead bloodhound={bloodhoundRemoteConfig} 
                    datasource={datasetConfig}
                    customEvents = {customEvents}
                    typeahead={typeaheadConfig}
                    placeHolder="A remote call + custom template" />,
    document.getElementById('#typeaheadDivRpc')
);

The awkward looking syntax above is JSX. Browserify will take care of the JSX->JS conversion for you. I setup a grunt watch task that will convert your JSX file example.js into ES5 compliant javascript anytime it changes. You can invoke this task by running the command below.

grunt watch:example --src-file="./dist/example.js"

Confirm that everything checks out by opening up a browser and going to the example at %CWD%/example/myComponent.html

And that’s it. Feel free to drop me an email if you run into issues.

Erik

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s