API.bible Logo

Documentation Navigation

Searching

Table of Contents

The search page has been linked to from most of the other pages and now we'll create this final page.

HTML - search.html

Start with the same HTML from before. Update the section between the div tags with class subheadings with:

<h2>Search results for:</h2>
<h3 id="viewing"></h3>

And update the section between the main tags with:

<div id="search-nav-top" class="search-nav search-nav-top"></div>
<div id="results-list" class="search-results-list list-container"></div>
<div id="search-nav-bottom" class="search-nav search-nav-bottom"></div>

Keep the link to the FUMS JavaScript file.

##JavaScript - search.html

const resultsList = document.querySelector(`#results-list`);
const searchInput = document.querySelector(`#search-input`);
const searchNavTop = document.querySelector(`#search-nav-top`);
const searchNavBottom = document.querySelector(`#search-nav-bottom`);
const bibleVersionID = getParameterByName(`version`) || `06125adad2d5898a-01`;
const abbreviation = getParameterByName(`abbr`) || "ASV";
const query = getParameterByName(`query`);
if (query) {
document.querySelector(`#viewing`).innerHTML = query;
search(query);
}
function search(searchText, offset = 0) {
searchInput.value = searchText;
getResults(searchText, offset).then((data) => {
let resultsHTML = ``;
if (data.verses) {
if (!data.verses[0]) {
searchNavTop.innerHTML = ``;
searchNavBottom.innerHTML = ``;
resultsHTML = `<div class="no-results">☹️ No results. Try <a href="index.html">changing versions?</a></div>`;
} else {
const [topSearchNavHTML, searchNavHTML] = buildNav(
offset,
data.total,
searchText
);
searchNavTop.innerHTML = topSearchNavHTML;
searchNavBottom.innerHTML = searchNavHTML;
resultsHTML += `<ul>`;
for (let verse of data.verses) {
resultsHTML += `<li>
<h5>${verse.reference}</h5>
<div class="text not-eb-container">${verse.text}</div>
<a href="verse.html?version=${bibleVersionID}&abbr=${abbreviation}&chapter=${verse.chapterId}">view chapter</a>
</li>`;
}
resultsHTML += `<ul>`;
}
}
if (data.passages) {
searchNavTop.innerHTML = ``;
searchNavBottom.innerHTML = ``;
if (!data.passages[0]) {
resultsHTML = `<div class="no-results">☹️ No results. Try <a href="index.html">changing versions?</a></div>`;
} else {
resultsHTML += `<ul>`;
for (let passage of data.passages) {
resultsHTML += `<li>
<h5>${passage.reference}</h5>
<div class="text eb-container">${passage.content}</div>
<a href="verse.html?version=${bibleVersionID}&abbr=${abbreviation}&chapter=${passage.chapterIds[0]}">view chapter</a>
<br>
</li>`;
}
resultsHTML += `</ul>`;
}
}
resultsList.innerHTML = resultsHTML;
});
}
function buildNav(offset, total, searchText) {
const topSearchNavHTML = `<span class="results-count">Showing <b>${
offset * 10 + 1
}-${
offset * 10 + 10 > total ? total : offset * 10 + 10
}</b> of <b>${total}</b> results.</span>`;
let searchNavHTML = `<span class="results-current-page"> Current page: <b>${
offset + 1
}</b></span>`;
if (offset > 0 || total / 10 > offset + 1) {
searchNavHTML += `<span class="results-nav">`;
}
if (offset > 0) {
searchNavHTML += `<button onclick="search('${searchText}', ${
offset - 1
})">Previous Page</button>`;
}
if (total / 10 > offset + 1) {
searchNavHTML += `<button onclick="search('${searchText}', ${
offset + 1
})">Next Page</button>`;
}
if (offset > 0 || total / 10 > offset + 1) {
searchNavHTML += `</span>`;
}
return [topSearchNavHTML, searchNavHTML];
}
function getResults(searchText, offset = 0) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.addEventListener(`readystatechange`, function () {
if (this.readyState === this.DONE) {
const { data, meta } = JSON.parse(this.responseText);
_BAPI.t(meta.fumsId);
resolve(data);
}
});
xhr.open(
`GET`,
`https://api.scripture.api.bible/v1/bibles/${bibleVersionID}/search?query=${searchText}&offset=${offset}`
);
xhr.setRequestHeader(`api-key`, API_KEY);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
}

In line 97, notice that all the data is returned. We don't break out specific fields like usual. While the URL for a search (line 101) is the same whether a user is searching for a passage or keyword, the data returned from the API is different for each case. For a passage search (i.e. 'John 3:16-19'), the data has an attribute called passages. For a keyword search (i.e. 'kingdom'), the data has an attribute called verses. This is because a passage search can return multiple verses in a single result, while a keyword search returns each verse individually in an array.

See lines 19-39 to see how we display a list of verses. See lines 41-58 to see how we display passages.

Another tricky part of this code is displaying the navigation. On an API call for a search, an offset can be included. This refers to the page number of the results. So for a search result set that includes 100 verses, you can just get 10 at a time. In the buildNav function on lines 64-85, you can see how we do some simple math to display page numbers and which results are being displayed.

Like before, include the getParameterByName and searchButton functions from the previous pages."