How to Integrate Elasticsearch into a Web App Using NodeJS and Express - Part 2
Add a front-end to the app
We made a great deal of progress in Part 1. We’ve proven we can interact with Elasticsearch through the browser, but so far our app is not at all user friendly. In this section we’ll add a basic user interface to allow us to interact with Elasticsearch with greater ease. We’ll be using Bootstrap and jQuery which will allow us to create a decent looking site up very quickly.
All we’ll add to the interface will be: A h1 title A form with textarea and a submit button to search articles * An empty div where we will add a table of our results with jQuery
Here’s the html for our index.html page:
File: search-articles/public/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <title>Search Articles</title> </head> <body> <h1>Search Articles</h1> <form class="clearfix mb-4" action="POST"> <div class="form-group"> <label for="search-title">Search for Titles</label> <textarea class="form-control" id="searchTitle" aria-describedby="search-title" placeholder="Elasticsearch on NodeJS"></textarea> </div> <button id="submitSearchTitle" class="btn btn-primary float-right">Submit</button> </form> <div id="tableDiv"> </div> <script src="https://code.jquery.com/jquery-3.4.0.min.js" integrity="sha256-BJeo0qm959uMBGb65z40ejJYGSgR7REI4+CW1fNKwOg=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> <script src="/js/index.js"></script> </body> </html> |
Notice we also linked to a javascript file index.js
which we will create in the upcoming step. Right now let’s just check that your home returns our new index.html
document. We won’t worry about functionality at this point.
Now we have a user interface but the buttons do nothing. We need to use javascript and jQuery to make it communicate with our backend (app.js) and display results.
Now we create our index.js
file to handle when users click the Search button. Let’s discuss what this file needs to do exactly:
- When the search button is clicked, it needs to read the value in the text field.
- It should make an ajax request to our server running on
localhost:3000/search-title/:title
and replace:title
with the user entered search term. - When it receives the results it should parse the results into a table and display the table.
Here’s our index.js file that accomplishes those goals:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | $(document).ready(function () { // Get references to page elements var $titleSearchText = $("#searchTitle"); var $submitTitleSearchButton = $("#submitSearchTitle"); var $logParagraph = $("#log").hide(); // The searchAPI object contains methods for each kind of request we'll make var searchAPI = { searchByTitle: function(title) { return $.ajax({ url: "/search-title/" + title, type: "GET" }); } }; var handleSubmitTitleSearch = function(event) { event.preventDefault(); var searchTerm = $titleSearchText.val().trim(); searchAPI.searchByTitle(searchTerm).then(function(resp) { var data = []; data[0] = ["ID", "Title", "Meta Description", "Meta Keywords", "Categories", "Tags", "Status"]; var hitsArray = resp.hits.hits; hitsArray.forEach(function(eachArticle) { data.push([eachArticle._id, eachArticle._source['Title'], eachArticle._source['Meta Description'], eachArticle._source['Meta Keywords'], eachArticle._source['Categories'], eachArticle._source['Tags'], eachArticle._source['Status']]); }); var articlesTable = makeTable($("#tableDiv"), data); }); // Clear out search field $searchTitlesButton.val(""); }; function makeTable(container, data) { var table = $("<table/>").addClass('table table-striped'); $.each(data, function(rowIndex, r) { var row = $("<tr/>"); $.each(r, function(colIndex, c) { row.append($("<t"+(rowIndex == 0 ? "h" : "d")+"/>").text(c)); }); table.append(row); }); return container.html(table); } // Add event listeners to the submit button $submitTitleSearchButton.on("click", handleSubmitTitleSearch); }); |
There’s a lot of code here so let’s go over the main points.
At the end of the file we added an event listener to our submit button which calls the handleSubmitTitleSearch
function which kicks off the whole process.
The search value is taken from the search box using jQuery.
Now that we have the search text we call searchAPI.searchByTitle(searchTerm)
which makes a request to the /search-title/:searchTerm
that we made using Express.
When we receive the response we parse the results into an HTML table and add it into the empty div.
The Final App
We’ve done it! We’ve created a simple web app that uses Elasticsearch to search an index.
Conclusion
In this tutorial we made a web application that takes a user’s query and then executes a search on a set of data using Elasticsearch’s advanced query capabilities. This type of functionality is extremely useful in improving any app’s user experience. We hope you can apply some of what you learned here to integrate Elasticsearch into your own web application.
Pilot the ObjectRocket Platform Free!
Try Fully-Managed CockroachDB, Elasticsearch, MongoDB, PostgreSQL (Beta) or Redis.
Get Started