Sharing templates between PHP and JavaScript

At work, we had a need to share templates between PHP and JavaScript. We had 2 paths to search results data. The first is from doing a dynamic search using AJAX and the results would be displayed by JavaScript. The second path was a way of browsing through the website and showing search results based on the browse selections. This path was server based and would be generated by PHP.

The search results would be displayed in cards, so we wanted to share the card template between both server side and browser. We saved a copy of the card template in the /public/views directory. This is a sample of what the card template looked like:

<div class="card">
  <div class="card_searchCard">
    <h1 class="card_name clearfix"><a href="{{ url }}">{{ display_name }}</a></h1>
    <div class="card_specialty">
      <span>{{ specialty }}</span>
    </div>
  </div>
  <div class="card__body clearfix">
    <div class="card__address row">
      {{ address1 }}
      {{ address2 }}<br>
      {{ city }}, {{ state }} {{ zip }}
    </div>
  </div>
</div>

To use this template in PHP, we settled on using Mustache PHP. A rough example of how we used it to render our results is:

$mustache = new Mustache_Engine(array(
    'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__) . '/../../public/views'),
));

$cards = array();
$template   = 'professionalCard';
foreach ($results as $result) {
    $cards[] = $mustache->render($template, $result);
}

This basically takes each result and renders it through the Mustache PHP templating engine. We saved the output of each result as a card and then would use those cards later.

It was trickier to use this from JavaScript, because we had to load the template from the web server to have it available for use. We decided to use MustacheJS for doing the JavaScript rendering. Normally, I would include the template with a script tag. However, if I included the code needed to make the template work in a script tag, the same file would not work with the PHP rendering. So the template files only contained the template with no extra code.

Here are the functions we setup for retrieving the template and rendering it with data:

function render(tmpl_name, tmpl_data) {
  var template;
  template = getTemplate(tmpl_name);
  return Mustache.render(template, tmpl_data);
}
function getTemplate(tmpl_name) {
  if ( !getTemplate.tmpl_cache ) {
    getTemplate.tmpl_cache = {};
  }

  if ( ! getTemplate.tmpl_cache[tmpl_name] ) {
    var tmpl_dir = '/views';
    var tmpl_url = tmpl_dir + '/' + tmpl_name + '.mustache';
    var tmpl_string;
    $.ajax({
        url: tmpl_url,
        method: 'GET',
        async: true,
        success: function(data) {
          tmpl_string = data;
          getTemplate.tmpl_cache[tmpl_name] = _.template(tmpl_string);
        }
    });
  }
  return getTemplate.tmpl_cache[tmpl_name];
}

Here is how we used those functions:

for (var i = 0; i < cardHits.length; ++i) {
  var hit = cardHits[i];
  var rendered_html = render(templ_name, hit);

  // render the hit
  res += rendered_html;
}
$('#hits').html(res);

We chose to make sure the templates were preloaded before they were needed, so we added this document ready function:

<script>
  $( document ).ready(function() {
    getTemplate('professionalCard');
    getTemplate('facilityCard');
  });
</script>

When we didn't preload the templates, we would get errors unless we made the AJAX call to load the template a synchronous call. I didn't like having a blocking function, so opted to load the templates at document ready.

If you have any questions or suggestions on alternate solutions, please leave a comment.

Preventing backspace from navigating your web page

I was running into problems where a user would have clicked outside of an input box and then type a backspace key and have the webpage navigate back one page. I tried a couple of solutions of my own, but they weren’t working.

I found this Stackoverflow solution which fixed the problem.


// Prevent the backspace key from navigating back.
$(document).unbind('keydown').bind('keydown', function (event) {
var doPrevent = false;
if (event.keyCode === 8) {
var d = event.srcElement || event.target;
if ((d.tagName.toUpperCase() === 'INPUT' &&
(
d.type.toUpperCase() === 'TEXT' ||
d.type.toUpperCase() === 'PASSWORD' ||
d.type.toUpperCase() === 'FILE' ||
d.type.toUpperCase() === 'EMAIL' ||
d.type.toUpperCase() === 'SEARCH' ||
d.type.toUpperCase() === 'DATE' )
) ||
d.tagName.toUpperCase() === 'TEXTAREA') {
doPrevent = d.readOnly || d.disabled;
}
else {
doPrevent = true;
}
}

if (doPrevent) {
event.preventDefault();
}
});

Knockout Auto-complete

I have been using knockout.js extensively in a recent project. I have enjoyed using it. The two-way data-binding has really simplified syncing the display and data, as well as posting data back to the server. I have found the documentation to be superb. Anything that I didn’t find in the documentation, I was able to learn with a quick google and usually found the result I needed on stackoverflow.com.

One feature that wasn’t explained well in the documentation was linking knockout to jQueryUI’s Auto-complete. I found several other blog posts from other people that had implemented it, but I think this post provided the best implementation. There were a couple of items that I tweaked to make it work closer to the way I wanted.

The first change was in the knockout custom binding. On the input text box, I had also defined a change event binding. The event binding was not getting called. There is a function named updateElementValueWithLabel in the definition that is called whenever an item was selected, changed or focused. I added this code to the bottom of the function:

if(typeof allBindings.event.change !== "undefined") {
allBindings.event.change();
}

This code enabled the change event binding to be called. It did create another problem. The above function was also being called when on option was moused over which triggered a focus event in the autocomplete plugin. I didn’t need the change event fired on just receiving focus, so this led to the second change I made.

In the jQueryUI section of the code, I changed the focus option to run just one line of code instead of calling the updateElementValueWithLabel function. That code was:
$(element).val(ui.item.label);
That line placed the option value in the html text box. When someone tabbed out or hit the enter key, the select/change functions would then be called.

I appreciate all the work the original author put in to develop this code. It saved me a tremendous amount of time in figuring out how to implement this and I only needed to make some minor tweaks to get it to work the way I needed it. Thanks Cameron.

Knockout.js

I have recently started using knockoutjs.com. I have been looking at other frameworks for a while, but I finally settled on using knockout. I like the clean code you can use. I never liked having to start your objects/classes by extending a framework base class. There is some KO specific code that you have to include, but it doesn’t take over your code.

I like Durandal as well, but it is in the process of being phased out. The creator of that framework is now on the Angular 2.0 team and will be integrating features of Durandal into Angular. It is unclear when Angular 2.0 will be released and I didn’t want to start using a framework knowing an eventual migration was in the works.

Stay tuned for more Knockout related posts.

JavaScript framework

I have been reviewing JavaScript frameworks. I have not been satisfied with the popular frameworks. I recently started looking at Durandal. It is based on Require.js so it is easy to create modules to organize your code. From what I have read, you do not have to start from a base durandal object. You just work with POJO (plain old javascript objects). That way you can also use your modules in non-durandal code as well. This is definitely a framework I am going to spend more time investigating.

Neat JavaScript trick

I have been reading Secrets of the JavaScript Ninja and learned an new idea. John Resig showed how to cache DOM elements by creating a cache inside of a function. He refers to this as a self-memoizing function and there is an example on page 75. Here is his example:

function getElements(name) {
  if (!getElements.cache) getElements.cache = {};
  return getElements.cache[name] = getElements.cache[name] || 
         document.getElementsByTagName(name);
}

I can  already think of where I can use this to improve performance on a website.