How to implement our Facet Engine in your own website - ΩJr. Software Articles and Products

This information lives on a web page hosted at the following web address: 'https://www.omegajunior.net/code/'.

A.E.Veltstra
May 20, 2014

A technical guide to OmegaJunior's javascript-based search results filter.

Facet Engines are a great interface for filtering large amounts of data. The zjrFacetEngine adapts to whatever meta data you throw at it. But just how do you implement it?

A word from a sponsor:


You could of course,

set up an appointment now, for a free online call

to hire me for an implementation session or instruction.

You can also read this article. You need to understand Javascript. Choose wisely.


Examples of Facet Engines

We have used our own facet engine in several places:

Our Facet Engine shows a listing of search results, and on its left, a bunch of filters (which we call “facets”, hence the term “facet engine”). It remembers the filter choices if the user’s browser allows that. It adapts to the facets defined by you. (Explanation follows below.)


Preparations

First off: download both the zjrJS Framework and the zjrFacetEngine. You can find download links at the end of this article. Download the latest version and upload the javascript files to your webserver, to a central location.

Next: link the zjrJS Framework to the web pages in which you want to use it. An HTMLScriptElement inside the HTMLHeadElement should do nicely:

<script src="/zjrJS.versionxxxxx.js"></script>
Replace the text “versionxxxxx” with the actual version number.

Third, load the zjrFacetEngine and tell it what to do. Below an example of a real configuration like we use ourselves on this website. After the code follows the explanation.

<script>
zjrJS.Doc.lS("/facetEngine.versionxxxxx.js");
var my = ({});

my.FacetEngineLoaded = function() {
"use strict";
zjrFacetEngine.init('/myDataFile.20131111t1611.js');
};
</script>



Explanation of the above code:

First we load the actual facet engine into the browser’s memory. Notice the lS()-function’s argument: “/zjrFacetEngine.versionxxxx.js”. This URI has to point from the web page in which you wish to use it, to the web address on the same web server, where you placed the facet engine javascript file. Remember to specify the correct version number of the facet engine.

Now, when the browser is done loading the facet engine javascript file, the facet engine will start the my.FacetEngineLoaded() function. It expects a function with exactly that name. That means it also expect a namespace object named “my”, which is why we declare it as an object in the script above.

The my.FacetEngineLoaded() function above does just 1 thing: it tells the facet engine where to find its search results data. The init() function takes a single argument. This URI has to point to the web address of that search results data file, which should live on the same server as the web page in which you want to use the facet engine.

Below we will discuss what this search results data file should look like. First, some additional functions of the facet engine.


Additional Functions

Facet Order

By default, the facet engine will show its facets in the order it finds in the search results data file. Sometimes it is useful to show them in a different order, or avoid showing some facets. For that reason, the zjrFacetEngine.Config object knows a setting named “facetOrder”. We could set it like this:

my.FacetEngineLoaded = function() {
"use strict";
zjrFacetEngine.Config.facetOrder = [ "content\x20type", "difficulty", "voices\x20range", "duration\x20range", "year", "download\x20range", "topics" ];
zjrFacetEngine.init('/myDataFile.20131111t1611.js');
};


As you notice, the facetOrder property takes an array with names. These reflect the facet names specified in the search results data file. The engine will show the facets in the order specified in that array. Any name it fails to recognise as a facet will be ignored. Any facet not mentioned in the facetOrder setting will be ignored, too (except when that setting is empty or null).


Language Choice

The Facet Engine knows 3 languages at the moment: English, German, and Dutch. It uses phrases and words from these languages in its user interface. (It does not care about the language of your search results data file or facet names.)

By default, the facet engine’s user interface is displayed with English words. To switch to Dutch, we need to specify the desired language. Therefore, the zjrFacetEngine.Config object knows a setting called “currentLocale”. We can set it to Dutch be specifying the locale “nl” like this:

my.FacetEngineLoaded = function() {
"use strict";
zjrFacetEngine.Config.currentLocale = "nl";
zjrFacetEngine.init('/myDutchDataFile.20131111t1611.js');
};


For German, set the currentLocale to “de”.

If you wish to display any other language, please let me know.


The Search Results Data File

It is a javascript file of which the contents could be formatted as JSON. The engine is fast enough to display thousands of search results in seconds, but we really advise against offering more than, say, 300 results.

If your search results come from a database, you could build a middleware (PHP, C#) or back-end (SQL) function that actually performs a search on the database, and then formats the results into JSON, as sampled below.

If you hand-code your search results, you can create a JSON-formatted file as sampled below:


Sample File

Here a sample from one of our data files:
if (typeof zjrFacetEngine === "undefined") {
var zjrFacetEngine = ({});
}

zjrFacetEngine.data = [
({
title: "Day of Heroes",
desc: "3-Voice theme by A.E.Veltstra, to remember our heroes and ancestors. Free.",
thumbnail: "/images/day-of-heroes-128.jpg",
url: "/muziek/?id=day-of-heroes",
meta: ({
"content\x20type": "description with audio",
year: "2013",
difficulty: "2",
"voices\x20range": "1 - 5",
"voices\x20exact": "3",
"duration\x20range": "0:30 - 1:00",
"duration\x20exact": "0:37",
"download\x20range": "0 - 0.5MB",
"download\x20exact": "70KB",
topics: [ "midi", "pdf", "download", "sheet music", "original", "remembrance" ]
})
})
];

zjrFacetEngine.callback();



Explanation of the Sample File

We start out by ensuring a browser memory object exists that is named “zjrFacetEngine”. Next, we fill its “data” array. Each search result is an item in the array, specified as a JSON object literal. The sample file above shows a single search result.

The search result specification follows this pattern:
String title: the caption shown to identify the search result;
String desc: an additional description;
URI thumbnail: the web address of an image shown with the search result;
URI url: the web address where the user can find more information about the search result;
Object meta: another JSON object literal specifying values per facet.

Each property is optional, meaning it can be left out safely. You can add other properties, which will be ignored.

Note that the strings (texts) are Javascript ones, rather than HTML ones, and thus require escaping according to Javascript string rules. If you are unfamiliar with this concept, try Google or hire me for a consult.

The "meta" object defines facet names and their values. In the sample file above, we defined facets that fit our listing of music samples. We can define any face of our liking, simply by specifying a name. For instance, in our Portfolio, we specify facets like this:

meta: ({
employer: "Colours",
year: "2012",
contenttype: "image (jpg)",
technologies: [ "jquery", "jquery-ui", "css3", "html5", "javascript", "dximagetransform", "960 grid", "conditional comments" ],
topics: [ "phenc", "usability testing", "front-end", "content creation", "prototyping" ]
})


The Facet Engine will automatically discover the meta items you create and use them as facets. It will automatically recognise whether a facet should contain a single term or an array of terms. (The only requirement is that you always use the same kind for the same facet: if you once use an array for a facet, you should always use an array for that same facet in the same data file.)

Since the facet names are derived from the meta properties, you are required to specify them in a way Javascript recognises. That limits us in several ways, reflected in the above 2 samples. If your knowledge about this is limited, try Google, or hire me for a consult.


That is all

Did we miss something? Something not as clear as we had hoped? Let us know in the comments below.

Thank you!

Need problem solving?

Talk to me. Let's meet for coffee or over lunch. Mail me at “code at omegajunior dot net”.