Create A Simple Look Up System

Author: Theodore Odeluga

The source files for this project can be downloaded from here

Most of the time, search tools are the domain of server-side programs. These products created with languages such as PHP or ASP.NET are often found on sites which are content heavy and need industrial strength code at the back end to enable them. But not always. Sometimes, small is beautiful. If you're a solo freelancer with a blog or running a website for a small business, a simpler option might be the better solution.

What if you don't have thousands of products or hundreds of articles about you in the press but you still want your users and customers to easily find information about you without too much effort? Even better, what if you want to keep all your information "in-house" where you can store and manage it more easily? A site based look up system might be the answer.

We're going to create such a system in this tutorial. It will be easy to manage, easy to extend and could integrate with any homepage (with a couple of buttons under a search bar beneath your website logo or title). It's also very portable as it's been built entirely for the client, so it doesn't need a server or any additional dependencies for its set up.

This project started out as an experiment and after pursuing it on and off, I decided to try and at least get it to the stage of a prototype or Minimum Viable Product. The original idea was to make something like a search engine, but other commitments took up my time so I shelved it. It remains something of a work in progress but it's still got potential and that's why I'm using it as the basis for this tutorial so that you can have a chance to play around with it as well.

This time round, I thought I'd make it the front end for looking up a dataset of images. The truth is, it can work with any type of data but I thought this example would be a good enough demonstration of what it can do. Besides, I had a few holiday snaps I wanted to use (:

Let's begin.

Create a new folder and name it 'app'. Open the folder and then fire up your editor.

Create a new HTML file then copy and paste this code into it.

<!DOCTYPE html>
<html>
<head>
<script src = "load.js"></script>
</head>
<body>
<div id = "itemnotfound"></div>
<form name = "myform">
<input type ="text" name="searchtext" size="30"></input>
<input type ="button" value="Search" onclick="Search();"></input>
<input type ="button" value="Clear" onclick="Clear();"></input>
</form>
</body>
</html>

This will form the structure of the app's interface. It's nothing special; just a search bar and a couple of buttons.

Save the file as 'index.html'.

We can take this opportunity to take a closer look at the program's logic.

You'll see the script tag linking to a file named 'load.js'. This is a small module which loads all the JavaScript we'll be using in the background. As future functionality is added to the project, this will keep the HTML from getting too cluttered. Instead of extending an ever expanding list of script tags, most of our JS will be referenced from another location.

Of course, load.js won't be our only script and while it needs to be kept outside the 'js' folder itself (it won't be able to load itself from there), we can stay organised by keeping all our scripting in 'js'.

Once we get into the body tag, we find a div named 'itemnotfound'. This will be the display object which tells the user when a search fails to find a match. Following this, we see the bulk of the HTML - our app's form.

We could have used some CSS here to make the front end more interesting. But this is just a demo and there are only three UI elements after all. A form works just fine.

The next element is an input object named 'searchtext', a textfield for the user to type their search. It allows up to 30 characters. You can increase this number but it's best to be economical. Larger amounts of text can be accommodated with a textarea instead of a textfield if you need more input from your user - but the names of our search objects will be short so a textfield does the job.

Following this is the search button. There's a bit of inline JavaScript here referencing the app's main function.

While I still believe in the best practice of the separation of concerns - keeping JavaScript, CSS and HTML apart to break up work and maintain efficient project management - writing inline can sometimes be useful for including small snippets of code.

The last element also uses inline script - a button to conveniently clear the text once the search is finished.

'Clear' does what it says on the tin and also removes messages from 'itemnotfound'.

Now for the JavaScript - the engine of our application.

Let's start with 'load.js'. Create a new file then copy and paste the code below into it, saving it under the name 'load.js'.

function load(filename, filetype){
if (filetype=="js"){
var fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript")
fileref.setAttribute("src", filename)
}

if (typeof fileref!="undefined") {
document.getElementsByTagName("head")[0].appendChild(fileref)
}
}

load("js/search.js", "js")
load("js/images.js", "js")

'load.js' is a bit of script I found in an article (sorry, can't remember the URL) which has proved useful time and time again. This module of less than 20 lines keeps your HTML from getting top heavy while allowing you to append more and more functionality to your project. So, thank you to whoever wrote this.

Next, we'll create the 'js' folder to contain the rest of our JavaScript.

Once that's done, open up the 'js' folder and create two more JavaScript files in it, one named 'images.js' and 'search.js' respectively.

We'll deal with 'search.js' first, the "nerve centre" of the whole project.

function Search(){
//Create a search field
var search_term = document.myform.searchtext.value;

//Set up a regular expression to block special characters
var re = /[!@#$%^&*(),.?":{}|<>]/g;

//Create a variable - for using the regular expression
var badinput = re.exec(myform.searchtext.value);

//Create a variable - for the 'Not Found' functionality
var noitem;

//Search the list
for(i=0; i < ImageList.length;i++){

//Match found
if(search_term == ImageList[i]){
window.document.write(''+''+search_term+'.jpg'+'');
}

//No match found
if(search_term != ImageList[i]){
noitem = document.getElementById("itemnotfound");
noitem.innerHTML = "Sorry, item not found.";
}

//Check for bad input (special characters)
if(badinput){
noitem.innerHTML = "Please enter a valid search term.";
}
} //Close loop
} //Close function

function Clear(){
document.myform.searchtext.value = "";
var noitem = document.getElementById("itemnotfound");
noitem.innerHTML = "";
}

There's a lot of commentary in 'search.js' but there's equally a lot of code, so let me explain.

The 'search_term' variable contains the value of the string representing the search. It's associated with the 'searchtext' textfield because of course this is how the app will receive the data which the user wants to search.

The 're' variable contains a regular expression - a collection of symbols based on special characters to capture an identified pattern (a specific series of characters and the structure they form) in a string.

The pattern being looked for here is exactly that; a collection of special characters. The purpose of the 're' regular expression (or 'regex') object is to identify them and meet a given condition if it finds them. (This will be tested by the 'badinput' variable further down).

If the condition returns true, it'll trigger a warning to the user not to input special characters.

The reason special characters are often blocked in forms for databases and search tools, is because it's possible to execute malicious code with them.

Programming code is made up of special characters after all and if an online form were to receive this as input, it's possible it could do damage to the database the application is accessing.

Next, as previously mentioned, the 'badinput' variable is initialised. It contains the 're' regex object, which in turn fires its exec function, whose single parameter is the the form's 'searchtext' textfield object - where it will find the dangerous characters if they are input.

After the initialisation of 'badinput' is the 'noitem' variable. This is simply a flag indicating failure to match a term in the ImageList array (contained in 'images.js').

The rest of the program is then dominated by arguably the most important part of the search tool - the loop iterating over the ImageList array every time a user initiates a search.

The loop generally targets the length of the ImageList array - rather than a specific number of elements. This enables the app to dynamically adapt to however big our image collection becomes.

Copy, paste and save the code for the search function into 'search.js' if you haven't done so already.

While you're at it, copy, paste and save the following code for the images array into 'images.js'.

var ImageList = new Array();
ImageList = [
{
"pic": {
"imagetext":"among the trees",
}
},
{
"pic": {
"imagetext":"ancient ruins",
}
},
{
"pic": {
"imagetext":"exotic tree",
}
},
{
"pic": {
"imagetext":"flower",
}
},
{
"pic": {
"imagetext":"forest",
}
},
{
"pic": {
"imagetext":"mountain above forest",
}
},
{
"pic": {
"imagetext":"mountain descent",
}
},
{
"pic": {
"imagetext":"statue",
}
},
{
"pic": {
"imagetext":"sunset",
}
},
{
"pic": {
"imagetext":"temple",
}
},
{
"pic": {
"imagetext":"theo and the mountain",
}
},
{
"pic": {
"imagetext":"trees in sunlight",
}
},
{
"pic": {
"imagetext":"view from the mountaintop",
}
},
]

The size of the loop in 'search' raises the question of how big a dataset should be when using JavaScript. This of course depends on a number of factors, including the type of data being handled.

While rich text documents for example (depending on their file size) might be a relatively lightweight problem to deal with, larger objects (i.e. videos - or even digital photographs) might mean a complete rethink about the applications design and the infrastructure to run it with.

Interestingly, while playing around with the code, using MP4 videos in the experiment, the loop object was able to iterate 1000,000 times before the browser started complaining. This suggested to me that theoretically at least, it's possible the search function could interrogate a maximum of 1 million records - quite a lot for a humble JavaScript app (as opposed to a 'proper' database tool such as Microsoft SQL Server and other enterprise level products).

This doesn't take any efficiency considerations into account though, so in a real world project, a technical decision might be taken that this approach is too risky and throw out any fantasies that this little demo could ever become the next Google. However, it does remain intriguing to try this stuff out. Small experiments lead to big discoveries.

If you are interested in building powerful search tools with JavaScript, this is possible with Node.js and the rest of the "MEAN stack" (though MySQL can also work with Node.js).

MEAN is an acronym for Mongo db, a database whose syntax is similar to JSON, Express.js (a routing framework to help you work with http requests), the Angular front end framework and of course Node, with it's provision of a local server. Check these technologies out when you've got a moment. They're an interesting bunch of tools and I'll be writing about them in future.

Caveats

This is a simple tool that doesn't yet have the capability of a scalable search engine. Depending on the amount of webspace you have available (pertinent if you're on a shared hosting package), you have to be mindful of how much data it works with. You'll need to experiment a little to ascertain what amount is appropriate. More seriously, you certainly can't treat it like a database. It's not a secure system, so you shouldn't store anything sensitive in the content folder or its associated JSON file.

Further Development

That about wraps things up though as a wise saying goes, "software is never finished, only abandonned."

This product is far from finished. One limitation you've noticed I'm sure, is that only one term can be searched at a time. Indeed, there isn't yet any functionality to find partial or multiple matches, an essential element of any search engine. This could be fixed with effective use of regex. I leave that as an exercise for you to have fun with.

Thanks for reading and I hope you found this useful. I'll be back soon with more content. In the meantime, stay safe and happy coding.