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.