REST-driven Search Component Tutorial
Follow the steps below to build an interactive book search tool on top of the Google Books API.
View a sample of the JSON results you will be using:
https://www.googleapis.com/books/v1/volumes?q=ice
Steps:
Step 1: Create baseline HTML
Using your favorite code editor, create
an HTML file named book-finder.html
with the content below.
book-finder.html
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>Book Finder</title>
</head>
<body>
<main>
<h1>Book Finder</h1>
</main>
</body>
</html>
Open book-finder.html
in your web browser to verify it displays properly.
Step 2: Add search component
Just after the h1
header line, insert the HTML for the search
input box and the submit button.
<main>
<h1>Book Finder</h1>
<label>
Search:
<input placeholder="Enter terms" autofocus>
</label>
<button>Find</button>
</main>
Now we need some HTML to display the search results.
Step 3: Add search results component
Just after the search component you added in the previous step, insert a div
tag
to hold a list of books. Then add the static HTML for a single book.
<div class=books>
<div class=book>
<img src=http://dnajs.org/graphics/sample-book-cover.jpg alt=cover>
<div>
<b>Title</b>
<p>Publisher</p>
<i>Price</i>
</div>
</div>
</div>
If you go to your browser and refresh the book-finder.html
page, you'll see the
sample book desperately needs some styling.
Step 4: Style search results
Add the following lines into the <head>
section:
<style>
body { font-family: sans-serif; margin: 30px; }
.book { display: table; background-color: lightblue;
padding: 10px; margin: 10px; }
.book img { width: 80px; margin-right: 10px; }
.book >div { display: inline-block; width: 400px;
vertical-align: top; }
</style>
The book-finder.html
page looks better with a little CSS, but it's still
completely static.
Next we'll turn the static book HTML into a template that can take JSON data.
Step 5: Define book template
Before we convert the static book HTML into a data-driven template, we need to know the structure of the data. Do this by manually examining the results of a sample search.
Below are the pertinent fields:
{
"totalItems": 1026,
"items": [
{
"id": "YfimjGQIo7gC",
"volumeInfo": {
"title": "The Book of Ice",
"publisher": "Subliminal Kid Inc",
"imageLinks": {
"thumbnail": "http://books.google.com/books/..."
}
},
"saleInfo": {
"listPrice": {
"amount": 9.99
}
}
}
]
}
The API returns a single object. The data we want is the list of books, which is the
items
array.
volumeInfo.imageLinks.thumbnail
(cover)volumeInfo.title
(title)volumeInfo.publisher
(publisher)saleInfo.listPrice.amount
(price)
Convert the book HTML into a template by changing the class book
to an ID
(name of the template) and adding the class dna-template
.
Also insert the data fields surrounded by double tildes (~~
) into the desired
spots within the template.
<div id=book class=dna-template>
<img src=~~volumeInfo.imageLinks.thumbnail~~ alt=cover>
<div>
<b>~~volumeInfo.title~~</b>
<p>~~volumeInfo.publisher~~</p>
<i>~~saleInfo.listPrice.amount~~</i>
</div>
</div>
Note:
For a production website, set the image src
attribute to
#
and specify the data field in the data-attr-src
attribute.
This apparoch maintains
valid HTML.
Now it's time to load some libraries that will help us build dynamic features.
Step 6: Load jQuery and dna.js
The easiest way to get the necessary CSS and JavaScript libraries is the pull them from a CDN.
First, add the following line into the <head>
section:
head
section
<link rel=stylesheet href=https://cdn.jsdelivr.net/dna.js/1.2/dna.css>
Then, add the following two lines just before the closing </body>
tag:
body
section
<script src=https://cdn.jsdelivr.net/jquery/3.2/jquery.min.js></script>
<script src=https://cdn.jsdelivr.net/dna.js/1.2/dna.min.js></script>
Go to your web browser and reload the book-finder.html
page.
Verify jQuery and dna.js loaded properly by going into the
JavaScript console
and entering the command:
dna.info();
Step 7: Wire up search callback
Start by writing the shell of a JavaScript function called findBooks()
.
Put the function just before the closing </body>
tag:
<script>
function findBooks(elem) {
var terms = $('input').val();
console.log(terms);
}
</script>
To wire up the funciton to the "Find" button, we'll use the dna-click
attribute.
The attribute tells dna.js which function to call when the user clicks the element.
Set the data-click
attribute to findBooks
on the
search component button
:
<button data-click=findBooks>Find</button>
Verify the click events are firing the callback by viewing the JavaScript console while clicking the "Find" button.
Step 8: Make REST call
Immediately after the console.log
line, insert the following code:
var url = 'https://www.googleapis.com/books/v1/volumes?q=' + terms;
function handleResults(data) {
dna.clone('book', data.items, { empty: true, fade: true });
}
$.getJSON(url, handleResults);
- Builds the REST URL
- Invokes jQuery's getJSON() function to call the Google Books API
- Passes the search results data to the templating engine.
The options { empty: true, fade: true }
tell dna.js to delete any previous
results before displaying the new results and to smoothly fade in the new results.
Go to your web browser and give it a whirl by searching for "laser".
Step 9: Smarten up the search field
Clicking the "Find" button may be simple, but it makes for a cumbersome user experience. We can leverage the smart update feature in dna.js to replace the button with automatic searching.
Delete the line of HTML for the <button>
, and update the
<input>
tag to be:
<input data-smart-update=findBooks placeholder="Enter terms" autofocus>
dna.js always passes the event target element into the callback.
The callback event now happens on the <input>
element, so we can replace
the old var terms = $('input').val();
line with a more robust line of code:
var terms = elem.val();
Hop back to your browser and verify that search results are returned continuously as you type in search terms.
Conclusion
That's a wrap!
Finished version:
Code:
book-finder.html
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>Book Finder</title>
<link rel=stylesheet href=https://cdn.jsdelivr.net/dna.js/1.2/dna.css>
<style>
body { font-family: sans-serif; margin: 30px; }
.book { display: table; background-color: lightblue;
padding: 10px; margin: 10px; }
.book img { width: 80px; margin-right: 10px; }
.book >div { display: inline-block; width: 400px;
vertical-align: top; }
</style>
</head>
<body>
<main>
<h1>Book Finder</h1>
<label>
Search:
<input data-smart-update=findBooks placeholder="Enter terms" autofocus>
</label>
<div class=books>
<div id=book class=dna-template>
<img src=~~volumeInfo.imageLinks.thumbnail~~ alt=cover>
<div>
<b>~~volumeInfo.title~~</b>
<p>~~volumeInfo.publisher~~</p>
<i>~~saleInfo.listPrice.amount~~</i>
</div>
</div>
</div>
</main>
<script src=https://cdn.jsdelivr.net/jquery/3.2/jquery.min.js></script>
<script src=https://cdn.jsdelivr.net/dna.js/1.2/dna.min.js></script>
<script>
function findBooks(elem) {
var terms = elem.val();
console.log(terms);
var url = 'https://www.googleapis.com/books/v1/volumes?q=' + terms;
function handleResults(data) {
dna.clone('book', data.items, { empty: true, fade: true });
}
$.getJSON(url, handleResults);
}
</script>
</body>
</html>
Hungry for more? Try building something using the Google Maps APIs Web Services.
For example, here's the JSON data for the geographic coordinates of Paris: maps.googleapis.com/maps/api/geocode/json?address=Paris
Questions and comments
Tweet your question or comment with #dnajs or post below.