I previously wrote an article on how to build a search engine in javascript that allow the user filter contents on a table using the onKeyUp event Listener. The search process only determined if the needle string has a strict match in the haystack string.
// pull the needle string from the input provided
let needleString = event.target.value;
// pull the haystack from the innerHTML of the row
let haystackString = row.innerHTML;
// hide all rows
row.hidden = true;
// strict search : searches for a copy of the
// needle string in the haystack
if (haystackString).inlcudes(needleString)) {
// ...
row.hidden = false;
}
The article provided details on how to do this and can be found here Instantaneous search with DOM API and JS.
However, what if the user wants to return rows that contain any of the words entered into the search input box. This is similar to the popular search engines like Google. The needle string entered into the search box is broken down into the constituent keywords and each keyword is searched in the haystack string.
In this article we are going to be building a JavaScript-based search engine for filtering tables contents. Using the String.split() method, each search string will be across a specified delimiter, returning an array of keywords. Each keyword is searched against the haystack using the String.includes() method. In order to automate the visibility of the table rows, (showing rows when they match, hiding them when they don’t), we will be relying on the provisions of the VueJS framework.
To start off we include the Vue framework to our base HTML
<script type="javascript" scr="./path/vue.js" />
Next, we define the search box, the text input to collect user searches. We set the v-model property to point to a node in the data store named “keywords”, this is where the search string will be stored.
<!-- -->
<input
type="text" class="input"
id="search-box" name="search-box"
placeholder="enter search keywords..."
v-model="keywords"
/>
<!-- -->
Then we define the table which will iterate through a list of items and list them in rows.
<!-- -->
<div id="app">
<table>
<!-- table header -->
<tr>
<td v-html="'#'"></td>
<td v-html="'Name'"></td>
<td v-html="'Type'"></td>
<td v-html="'Specialty'"></td>
</tr>
<!-- the list of items -->
<tr v-for="(item, idx) in list" >
<td v-html="idx"></td>
<td v-html="item.name"></td>
<td v-html="item.type"></td>
<td v-html="item.specialty"></td>
</tr>
</table>
</div>
<!-- -->
Next, we setup the Vue component.
let app = new Vue({
el: "app",
// the data store
data: {
// stores the keywords entered into the search box
keywords: "",
// stores the data items to be listed
list: {
{
"name": "Yurich Manakov",
"specialty": "Airworthiness",
"type": "Management",
},
{
"name": "Hank Fracas",
"specialty": "Air Traffic Services",
"type": "Inspector",
},
{
"name": "Magellan VanLandingham",
"specialty": "Flight Operations",
"type": "Management",
},
{
"name": "Carl Discotheque",
"specialty": "Aerodromes",
"type": "Inspector",
},
{
"name": "Teddy Arugula",
"specialty": "Meteorology and Aviation Security",
"type": "Inspector",
},
{
"name": "Ludwig Von Instagram",
"specialty": "Aeronautical Telecommunications",
"type": "Inspector",
},
{
"name": "Carlos Waterside",
"specialty": "Aeronautical Information Services",
"type": "Inspector",
}
},
},
// the methods
method: {
/**
* Keyword Search
* This will perform the keyword search using the contents
* of the keywords node in the data store
*
* @param object
* @return bool
*/
keywordSearch: (object) {
},
},
// computed
computed: {
/**
* Filtered List
* This is a Vue computed method that watches for changes in the keywords
* and modified the filtered list items to be displayed in the DOM
*
* @param null
* @return Object Array
*/
filteredList: () {
},
},
})
Next we define the keyword search method.
/**
* Keyword Search
* This will perform the keyword search using the contents
* of the keywords node in the data store
*
* @param object
* @return bool
*/
keywordSearch: (object) {
// define the haystack
let haystack = Object
// fetch all the values in the object
.values(object)
// merge the array into a string, the separator here does not matter
.join("~")
// convert to lowercase
.toLowerCase()
// initialize the separator, which for words in a sentence is a space, " "
let sep = " "
// if the search box is empty then return true
// so that the object row can be shown
if (
(app.keywords === undefined)
|| (app.keywords === null)
|| (app.keywords === "")
) { return true}
// prepare the needle
let keywordList = app.keywords.toLowerCase().split(sep)
// the total number of matches
let matches = 0
// iterate through the words in the search
Array.from(keywordList).forEach((word, wid) => {
// perform the search
if (haystack.includes(word)) {
// if a match is made, return true and end the method
matches++;
}
})
// matches were found for all the keyword items sent
if (matches === keywordList.length) {
// return true
return true
}
// non or incomplete matches, return false
return false
},
Then is the Filtered List method. Instead of creating eventListeners for user input in the search box, we will be relying on the Vue Computed property. This makes it easier to automate as Vue handles the row visibility of each row in the table based on a match to the keyword string.
/**
* Filtered List
* This is a Vue computed method that watches for
* changes in the keywords
* and modified the filtered list items to be displayed in the DOM
*
* @param null
* @return Object Array
*/
filteredList: () {
// initialize the list to be returned
filtered = []
// if the search box is empty
if (this.keywords.length <= 0) {
// return the entire list
return this.list
}
// iterate through the data store
Array
.from(this.list)
.forEach(
(item, iid) => {
// if the search has a match
if (this.keywordSearch(item)) {
// put the matched item to the returned list
filtered.push(item)
}
})
}
return filtered
},
After this is done, our Vue instance will look like this:
let app = new Vue({
el: "app",
// the data store
data: {
// stores the keywords entered into the search box
keywords: "",
// stores the data items to be listed
list: {
{
"name": "Ulrich Manakov",
"specialty": "Airworthiness",
"type": "Management",
},
{
"name": "Hank Fracas",
"specialty": "Air Traffic Services",
"type": "Inspector",
},
{
"name": "Magellan VanLandingham",
"specialty": "Flight Operations",
"type": "Management",
},
{
"name": "Carl Discotheque",
"specialty": "Aerodromes",
"type": "Inspector",
},
{
"name": "Teddy Arugula",
"specialty": "Meteorology and Aviation Security",
"type": "Inspector",
},
{
"name": "Ludwig Von Instagram",
"specialty": "Aeronautical Telecommunications",
"type": "Inspector",
},
{
"name": "Carlos Waterside",
"specialty": "Aeronautical Information Services",
"type": "Inspector",
},
},
},
// the methods
method: {
/**
* Keyword Search
* This will perform the keyword search using the contents
* of the keywords node in the data store
*
* @param object
* @return bool
*/
keywordSearch: (object) {
// define the haystack
let haystack = Object
// fetch all the values in the object
.values(object)
// merge the array into a string, thge seoarator here does not matter
.join("~")
// convert to lowercase
.toLowerCase()
// initialize the separator, which for words in a sentence is a space, " "
let sep = " "
// if the search box is empty then return true
// so that the object row can be shown
if (
(app.keywords === undefined)
|| (app.keywords === null)
|| (app.keywords === "")
) { return true}
// prepare the needle
let keywordList = app.keywords.toLowerCase().split(sep)
// the total number of matches
let matches = 0
// iterate through the words in the search
Array.from(keywordList).forEach((word, wid) => {
// perform the search
if (haystack.includes(word)) {
// if a match is made, return true and end the method
matches++;
}
})
// matches were found for all the keyword items sent
if (matches === keywordList.length) {
// return true
return true
}
// non or incomplete matches, return false
return false
},
},
// computed
computed: {
/**
* Filtered List
* This is a Vue computed method that watches for
* changes in the keywords
* and modified the filtered list items to be displayed in the DOM
*
* @param null
* @return Object Array
*/
filteredList: () {
// initialize the list to be returned
filtered = []
// if the search box is empty
if (this.keywords.length <= 0) {
// return the entire list
return this.list
}
// iterate through the data store
Array
.from(this.list)
.forEach(
(item, iid) => {
// if the search has a match
if (this.keywordSearch(item)) {
// put the matched item to the returned list
filtered.push(item)
}
})
// return the filtered list
return filtered
},
},
})
Then we go back to the table HTML and edit the iterated object, replacing the raw list from the data store with the computed filteredList
<!-- -->
<!-- the list of items -->
<tr v-for="(item, idx) in filteredList" >
<!-- ... -->
</tr>
<!-- -->
And we are done. Putting it all together, we will have the following:
<!-- include Vue -->
<script type="javascript" scr="./path/vue.js" />
<!-- search box -->
<input
type="text" class="input"
id="search-box" name="search-box"
placeholder="enter search keywords..."
v-model="keywords"
/>
<!-- table HTML -->
<div id="app">
<table>
<!-- table header -->
<tr>
<td v-html="'#'"></td>
<td v-html="'Name'"></td>
<td v-html="'Type'"></td>
<td v-html="'Specialty'"></td>
</tr>
<!-- the list of items -->
<tr v-for="(item, idx) in filteredList" >
<td v-html="idx + 1"></td>
<td v-html="item.name"></td>
<td v-html="item.type"></td>
<td v-html="item.specialty"></td>
</tr>
</table>
<!-- -->
</div>
let app = new Vue({
el: "app",
// the data store
data: {
// stores the keywords entered into the search box
keywords: "",
// stores the data items to be listed
list: {
{
"name": "Ulrich Manakov",
"specialty": "Airworthiness",
"type": "Management",
},
{
"name": "Hank Fracas",
"specialty": "Air Traffic Services",
"type": "Inspector",
},
{
"name": "Magellan VanLandingham",
"specialty": "Flight Operations",
"type": "Management",
},
{
"name": "Carl Discotheque",
"specialty": "Aerodromes",
"type": "Inspector",
},
{
"name": "Teddy Arugula",
"specialty": "Meteorology and Aviation Security",
"type": "Inspector",
},
{
"name": "Ludwig Von Instagram",
"specialty": "Aeronautical Telecommunications",
"type": "Inspector",
},
{
"name": "Carlos Waterside",
"specialty": "Aeronautical Information Services",
"type": "Inspector",
},
},
},
// the methods
method: {
/**
* Keyword Search
* This will perform the keyword search using the contents
* of the keywords node in the data store
*
* @param object
* @return bool
*/
keywordSearch: (object) {
// define the haystack
let haystack = Object
// fetch all the values in the object
.values(object)
// convert to lowercase
.toLowerCase()
// initialize the separator, which for words in a sentence is a space, " "
let sep = " "
// prepare the needle
let keywordList = this.keywords.split(sep)
foreach(word in keywordList) {
// perform the search
if (haystack.includes(word)) {
return true;
}
}
return false
},
},
// computed
computed: {
/**
* Filtered List
* This is a Vue computed method that watches for changes in the keywords
* and modified the filtered list items to be displayed in the DOM
*
* @param null
* @return Object Array
*/
filteredList () {
// initialize the list to be returned
filtered = []
// if the search box is empty
if (this.keywords.length <= 0) {
// return the entire list
return this.list
}
// iterate through the data store
Array
.from(this.list)
.forEach(
(item, iid) => {
// if the search has a match
if (this.keywordSearch(item)) {
// put the matched item to the returned list
filtered.push(item)
}
})
// return the filtered list
return filtered
},
},
},
})
0 likes