Digital Thoughts

typeahead template function

Posted on: March 16th, 2014 by taff No Comments

 

Sometimes when using typeahead you need to retrieve different data which for example links to a particular page as opposed to carrying out a search. The typeahead template function is just the job for this, but let's have a look at the data first. In the following example I will be retrieving two types of data. If you need help with this, look into retrieving multiple sources with typeahead. The first data retrieved is the search suggest which I won't go into deeper as this example concentrates on using the typeahead template function.

The JSON data I retrieved by the call to products.php has the following structure (this would be the data retrieved when typing netbook into the searchbar:

[
{"product_id":"1","value":"Aspire Netbook"},
{"product_id":"2","value":"ASUS Netbook"},
{"product_id":"3","value":"Lenova Netbook"}
]

Nothing to difficult here. The idea is that the data retrieved can be used to generate a direct link to the product, saving the need for a user search. Using a general MVC standard, the url would be product/details/product_id where product is the controller, details the action within said controller and product_id would be the parameter passed to our action If I want to visit the ASUS Netbook page, I would go to product/details/2. Let's see how the typeahead template function can help us to achieve this.

jQuery(document).ready(function () {
jQuery('#Search').typeahead([
{
limit: 5,
name: 'searchterms',
remote: '/searchterms.php?q=%QUERY',
header: '
<h3 class="suggest-elements">Search Terms</h3>
'
},
{
limit: 3,
name: 'products',
remote: /products.php?q=%QUERY,
header: '
<h3 class="suggest-elements">Products</h3>
',
template: function (data) {
return '
<p class="searchSuggest-product"><a href="/product/details/' + data.product_id + '">' + data.value + '</a></p>
';
}
}
]);
});

As you can see, the typeahead template function is a simple callback function that is passed a data array and returns some HTML. Although typeahead offers the ability to use Handlebars or Hogan to compile the template, as you can see on the typeahead examples page, I find this version better as it saves me using an additional javascript libarary. I hope this short example helps you get to grips with the typeahead template function. Feel free to comment if anything is unclear or you need further assistance

typeahead multiple sources

Posted on: March 2nd, 2014 by taff No Comments

 

Today I would like to continue the series on by going into retrieving multiple sources with typeahead. I recently went into how to limit the results with typeahead. This example goes into getting more than one dataset into your result. As I mentioned in the first post, I have two types of data one that retrieves the searchterms other users have used and the other to find relevant products in a database so lets look at retrieving both sources with a single call.

Retrieving multiple sources with typeahead

The example below shows how to retrieve multiple sources with typeahead. To assist the user with seeing where to suggestions are coming from, we have added a header parameter which is displayed above the dataset thus increasing legibility.

jQuery('#Search').typeahead([
{
limit: 3,
name: 'searchterms',
remote: '/searchterms.php?q=%QUERY',
header: '<h3 class="suggest-elements">Search Terms</h3>'
},
{
limit: 5,
name: 'products',
remote: /products.php?q=%QUERY,
header: '<h3 class="suggest-elements">Products</h3>'
}
]);

Note that we can individually set the number of results when retrieving multiple sources with typeahead. The example above collects 3 results from the searchterms query and five results from the products query. The datasets are separated with the respective headers. In the next tutorial we will go into using a custom template to directly link to the products page. The searchterms dataset will functionally stay the same, so that it simply changes the input field upon selection and fires the query.

typeahead – Limit results

Posted on: February 28th, 2014 by taff No Comments

 

I recently started using twitters typeahead for search suggestions. Although it works well out of the box, there were a couple of things I wanted to change. Currently I have typeahead doing two requests, one that retrieves the searchterms other users have used and the other to find relevant products in a database, but to start let's look how to go about limiting the number of results.

Limiting the number of results with typeahead

By default, typeahead limits the number of results to 5. I, however, only wanted the 3 closest results. Limiting the number of results with typeahead is simply achieved using the limit parameter as can be seen in the typeahead example below

jQuery('#Search').typeahead([
{
limit: 3,
remote: '/searchterms.php?q=%QUERY',
name: 'searchterms'
}
]);

The example has three parameters, the limit parameter that tells typeahead how many results to display, the remote parameter which tells typeahead where to get the data from and name which tells typeahead the name of the dataset. The code above limits the results to three. As you can see limiting the number of results with typeahead is a breeze with the correct parameter.

This code needs to be placed inside a document ready function or an equivalent to ensure execution when the page has loaded. It goes without saying but you obviously need to make a script call to typeahead.min.js. In the example above typeahead adds some javascript magic to the input field with the ID Search.

Although not entirely related to limiting the number of results with typeahead, in addition to the remote parameter, there are other ways of retrieving data. For example, if you have a set amount of data that you want to be cached client side, you may want to look into the prefetch parameter. I hope you like this short example of limiting the number of results with typeahead. Look forward to a couple of other examples such as requesting more than one type of data and how to build a custom template without using hogan.

Road Choice Touch Screen Game

Posted on: February 26th, 2014 by taff No Comments

 

RoadChoice-1This was a project to build a game which is presented upon a 42" touch screen. The user selects a product, for example Lighting. A garage door then closes, some Ajax magic happens in the background to acquire a random prize and the prize screen is then displayed. The prize screen displays what the user has won and a text related to the product they selected.

 

RoadChoice-2The database contains a number of items that can be won. Each item has a certain number of items available. When the item is won, the number is reduced. If that number reaches 0, it can no longer be won. The application is hosted on a Mac Mini with MAMP. The application uses PHP for the backend and mySQL for a database.

The frontend uses jQuery as a JavaScript framework. To ensure excellent flowing animations, the application uses webkit to take advantage of, for example, webkitTransitionEnd and can therefore only be viewed properly in Chrome or Safari. This was not a problem as it hosted on it's own machine. We took advantage of using Chrome in Kiosk mode. This was an sound choice.

The entire development process used GIT as the Versioning Control System. Once the development server has been locked down, I will post a link.

Loop through Input Elements in a DIV Tag with jQuery

Posted on: February 26th, 2014 by taff No Comments

 

Occasionally you need to loop through input elements prior to submission so that you can see what exactly is being submitted.
I like to use jQuery, the javascript framework of my choice for this. Although the title describes looping through input elements in a DIV Tag, you can use the following script to equally loop through elements in a FORM tag identically.

The following script will loop through input elements in the DIV tag with the ID nameOfDiv. You can, of course, use a different selector if you need the elements in multiple divs.

var $inputs = jQuery('#nameOfDiv :input');
var values = {};
$inputs.each(function() {
    console.log(values[this.name] = jQuery(this).val());
});
jQuery('#nameOfDiv').submit();

Using the jQuery each function we can loop through all the input elements in our div. For the example, I am simply outputting them into the console window, i.e. Firebug or the Chrome console.

 

This is a short entry on how to update jQuery's Slider immediately from an input field whenever it changes. There are quite a lot of events that we need to catch. The normal change event just doesn't cut it as it only fires when the the input field looses its focus. To allow us to update the jQuery Slider immediately, we need to use the keyup event. Every time a key is released the values of our field are immediately sent to the jQuery Slider. The other events include the input event which fires when the interface changes the value of our field. Because of Internet Explorer, which is buggy with this event, we have also added propertychange. When the cut and paste events trigger probably comes as no surprise.

Updating jQuery Slider Value immediately upon Input Change

jQuery( ".myInputs" ).bind("propertychange keyup input cut paste", function(event){
        jQuery( "#slider-id" ).slider( "values", [ jQuery( "#minimumValue" ).val(), jQuery( "#maximumValue" ).val() ] );
    });

We have bound the event to the elements with the class myInputs, in this case our input fields for the minimum and the maximum values. Whenever one or more of the events is triggered, the jQuery Slider values (I have a minimum and a maximum value) are updated with the values of our input fields. We don't have to loose focus for the slider to update, thanks to our keyup event. Marking the contents of a field and cutting it out or pasting content also triggers events mentioned above. All in all a sound solution to the problem.

HTML to PDF Generator

Posted on: December 29th, 2013 by taff No Comments

 

I've just finished building an HTML to PDF converter. The client couldn't find any plugin that met the requirements so they decided upon a custom solution which I had the privilege of building.

The first step was to find a PHP library that could convert HTML to PDF. I decided to go with MPDF, as a few tests had shown it to convert HTML to PDF really fast.

The first part of converting HTML to PDF was to get the HTML. I simply used the PHP function

$sourceCode = file_get_contents("http://www.domain.com/path/to/page.html");

We now have the Source Code stored in our $sourceCode variable. Simple and effective...unless the HTML isn't valid, which would cause problems later on.

The next step I took in converting the HTML to PDF is to remove the markup that I don't need. The advantages here are twofold:

1. Less HTML Markup to parse into PDF
2. Lowers the risk of invalid HTML Markup causing PDF generation to fail

Before I go "throwing away" markup that I don't need in my HTML to PDF script, I need to ensure that anything of use is kept. Theoretically there are two things that could be useful:

1. The contents of the title tag. I can use this to create a filename later on
2. The Print.CSS if I have one

Extract the page title with a regular expression

The first stage is to extract the page title with a regular expression. We'll save what we find in a variable. If we don't find anything we will create a generic title.

if (preg_match('/(.*?)<\/title>/is',$sourceCode,$found)) { $title = "PDF: " . $found[1]; } else { $title = "A PDF from somewhere"; } 

If we wanted to use a media='print' CSS stylesheet we would do it in a similar way but I have one defined especially to make the PDF look glossier ;-) So we don't need anything else from between the head tags, so let's clear that out. The php function strstr is perfect for this.

 $noheader = strstr($sourceCode, '');
$body = strstr($noheader, '', true);

which should get the body tags and whatever is in between into our $body tag.

Removing ID Attribute with a Regular Expression

Because certain ID's had been used more than once, which of course is invalid and would cause an exception to be thrown, I decided to simply remove all the ID's. For this I used a simple one-liner to allow the HTML to be parsed by MPDF later that looks like this:

$body = preg_replace('#\s(id)="[^"]+"#', '', $body);

My example HTML to PDF script had 2 different elements that I needed to be parsed, all of which are contained in a div with the class "content" a title, in a H5 tag (the only h5 tag in the markup), the content in one or more 'p' tags. PHP comes with the very useful DOMXpath and with my past knowledge of xpath, made things a breeze

$xpath = new DOMXpath($body);
$htmlElements = array();

Above we are simply preparing the HTML to be parsed.
The next step is to get our h5 element into a variable ready for parsing

$contentTitle = $xpath->query("//*[@class='content']/h5");
$contentElements = array();

$tmp_dom = new DOMDocument();
$tmp_dom->appendChild($tmp_dom->importNode($contentTitle, true));
$headerElement = $tmp_dom->saveHTML();
$htmlElements['header'] = $headerElements;

The same applies below, but because we don't know how many elements we have we need a foreach loop.

$elements = $xpath->query("//*[@class='content']/p");
$contentElements = array();
foreach ($elements as $e):
$tmp_dom = new DOMDocument();
$tmp_dom->appendChild($tmp_dom->importNode($e, true));
$contentElements[] = $tmp_dom->saveHTML();
endforeach;
$htmlElements['p'] = $contentElements;

All the content we need to convert from HTML to PDF is now stored in our $htmlElements array.

The rest is pretty easy thanks to MPDF.

include("path/to/libraries/mpdf.php");

$mpdf=new mPDF('c', 'A4', 0, 'Arial', 10, 10, 10, 10, 10, 10);
//The title we extracted earlier
$mpdf->SetTitle($title);
$mpdf->SetDisplayMode('fullpage');

Because I want to load a custom stylesheet just for the PDF generation, I simply do this

$stylesheet = file_get_contents('path/to/pdf_print.css');
$mpdf->WriteHTML($stylesheet,1);

The second parameter with the value 1 simply tells MPDF that this is a stylesheet and nothing else, the magic is then done.
We now just need to add our markup to the $mpdf variable like this:

$mpdf->WriteHTML("<body>");
$mpdf->WriteHTML("<h1>" . $htmlElements['header'] . "</h1>");
foreach ($htmlElements['p'] as $paragraph):
	$mpdf->WriteHTML($paragraph);
endforeach;
$mpdf->WriteHTML("</body>");
$mpdf->Output($filename,'I');

When we now execute our script it will force the browser to offer the page as a download. I hope this helps to show how easy it is to convert HTML to PDF.

jquery session cookie – HTML5 sessionStorage

Posted on: November 5th, 2013 by taff No Comments

 

I've always been a bit reluctant to using HTML5 that isn't globally supported, but recently I've been doing a lot of work on a mobile version of a website which means I get to use everything :-)

Whenever I used to need a jquery session cookie, i.e. a cookie that exists for a session and is accessible via javascript, I would use the excellent jQuery cookie plugin but with the (near) global support for sessionStorage and localStorage I think it will become a thing of the past.

sessionStorage - The HTML5 equivalent of a jquery session cookie

I needed a jquery session cookie to see if someone had already had the geolocation window and if so, surpress it until the next time the user visits the site. I could probably have done this just as quick with the cookie plugin but after taking a look at the sessionStorage support, decided it was the way to go.

jQuery(function () {
var hadLocationWindow = sessionStorage.getItem("hadLocationWindow");

if(hadLocationWindow == null || hadLocationWindow == 'undefined') {
sessionStorage.setItem("hadLocationWindow", "YES");
console.log("no location yet, offer geolocation");
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
}
} else {
console.log("you have seen this window before");
}

});

Viewing SessionStorage and localStorage Data

When it comes to sessionStorage and localStorage (the persistent version of storage), I use a firebug with a simple


console.log(sessionStorage);

normally to see what is happening. If I need to do more I can recommend the FireStorage Plus! Plugin

Another advantage is the ability to save large amounts of data which has no limit to the possibilities such as saving profile data to save querying the database so often thus making it even more useful than the jquery session cookie

Uncaught Gearman Exception

Posted on: October 20th, 2013 by taff No Comments

 

Using an older version of the most excellent Gearman (0.8.1), I came across a phenomena that wouldn't let me catch the ErrorException. Because I couldn't upgrade due to compatibility issues I had find the workaround.

Gearman Timeout Exception

The Gearman Timeout Exception occurred when the worker wasn't running when the runTasks() method was called. I thought I could prevent my worker file from expiring by using set_time_limit = 0; Unfortunately it didn't. So these were the problems that I faced:

  • Uncaught Gearman Exception setTimeout
  • Someway to reinstantiate the client worker, ideally when the exception happen
  • A cronjob to periodically check if the GearmanWorker is working

The Uncaught Gearman Exception

Although was initially the largest problem, it was in fact the easiest to solve by redefining the set_error_handler like so:

set_error_handler( array($this, 'gearman_error_handler'), -1 & ~E_NOTICE & ~E_USER_NOTICE);
$objGearmanClient->runTasks();
//reset error handler.
restore_error_handler();

public function gearman_error_handler($errno, $errstr, $errfile, $errline) {
if ($errno == 2) {
echo("A search went wrong");
} else {
$_log = \Logger::getInstance("preisvergleich_gearman_worker");
echo("A search went wrong because the Gearman Workers weren't running";
}
}

The last line resets back to the default error handling class that is implemented by the application

Reinstantiate the Gearman Client

I found something on StackOverflow that got me thinking. Why not build a class to monitor the Gearman Worker? In particularly as I had more that one worker running, albeit for different tasks, being able to check if the task was running would also come in handy for the cronjob check. Using shell_exec I was then able to restart the worker by executing the php file if and when the worker dies on me again.
That obviously goes a bit beyond catching Gearman Exceptions but could well be around in another blog post if someone finds it of interest. This is the method that I used:

protected static function callWorkerFile($strPathToWorker) {
 return shell_exec("nohup php " . $strPathToWorker . " > /dev/null & echo $!");
}

jQuery change url parameter value

Posted on: September 7th, 2013 by taff No Comments

 

Using jQuery to change the parameter of a url when an element, such as a select or a is clicked, can be done in a number of ways. Below are two examples.

Change URL parameter value by using the javascript split method

The simplest is probably something along these lines, although as we ill see later, the easiest is not always the best.

function changeFirstParam(href, newVal) {
//get our parameters into an array
params = href.split('&');
//this will only work if the first parameter is the one
//we need to change
var src = params[0].split('=');
//Remove the first value of the first parameter
params.shift();
//Give the first parameter a new value
src[1] = newVal;
//Join it all back up
var newUrl = ( src.join('=') + params.join('&'));
//Return our new url
return newUrl;
}

var href = changeFirstParam("http://domain.com?var=thisIsOld&a=1&b=2&c=3","theNewValue");
console.log(href);

The above script splits the parameters into an array, then changes the first parameters value. This will probably suffice for most cases but what if we aren't sure which position our parameter will have? I want to keep my scripts as dynamic as possible to accomodate future changes in the backend, thus even though the overhead is slightly higher I prefer something with a regular expression.

Change URL parameter value with a Javascript Regular Expression (RegEx)

function changeParam(href, newVal) {
var tmpRegex = new RegExp("(var=)[a-z]+", 'ig');
return replace(tmpRegex, '$1'+newVal);
}

var href = changeParam("http://domain.com?var=thisIsOld&bca=something&b=2&c=3","theNewValue");
console.log(href);

This will simply replace the value of our var parameter no matter what position it has in the parameter list. Not bad, but what if I need an identical function when a radio button value is changed as well. The solution of course? A variable! This is why the above example uses a RegExp constructor. If we had tried to put a variable directly in the replace method it wouldn't work.

Change URL parameter value with a variable in a Javascript Regular Expression (RegEx)

function changeParamByName(href, paramName, newVal) {
var tmpRegex = new RegExp("(" + paramName + "=)[a-z]+", 'ig');
return href.replace(tmpRegex, '$1'+newVal);
}

var href = changeParamByName("http://domain.com?var=thisIsOld&bca=something&b=2&c=3","bca","theNewValue");
console.log(href);

The following is an example of some html where I used the following script. It is a simple ul list whereby the list element has a data-language attribute. When someone clicks on a list element, we want the favLanguage parameter value to change accordingly:

Change URL Parameter Value when Element clicked with jQuery

<ul id="language">
	<li data-language="php">PHP</li>
	<li data-language="asp">ASP</li>
	<li data-language="js">Javascript</li>
</ul>
<a id="languageLink" href="http://domain.com/index.php?favLanguage=default">Submit Language</a>
var paramName = "favLanguage";
jQuery("#language li").click( function(e) {
jQuery("#languageLink").attr('href', function(i,a){
var tmpRegex = new RegExp("(" + paramName + "=)[a-z]+", 'ig');
return a.replace(tmpRegex, '$1'+e.target.dataset.language);
});
});

We've done away with an external function now, which should increase the readability, although if we needed the functionality on a different element too, we would outsource it. When an item from the list is clicked the href attribute is changed.