Hans Pede Hans Pede - 3 months ago 16
jQuery Question

handlebars and countdown inside template

Using Final Countdown Plugin and Handlebars.js.

Both plugins works great, separately. The following

<div>
will give me a countdown (here countdown to 2017/01/01):

<div id="getting-started"></div>
<script type="text/javascript">
$("#getting-started").countdown("2017/01/01", function(event) {
$(this).text(
event.strftime('%D days %H:%M:%S')
);
});
</script>


I have a simple handlebars example here:

<script type ="mustache/x.tmpl" id="helloTmpl">
{{#each this}}
{{endTime}}
{{/each}}
</script>


Where
{{endTime}}
is the end time I would like a countdown to (instead of 2017/01/01). It is inside the
{{#each}}
loop and there will run many
{{endTime}}
.

Anyone know an idea to make this possible? And get a countdown for every
{{endTime}}
? I tried to put the above countdown plugin into a helper but with no success and it became a bit messy. Thanks in advance.

EDIT: Result

Thanks @76484. By puzzling with your example I now got it to work with my setup, great! I run
function populate()
every 3-5 sec to refresh my template with new data. This now means I also have to run the countdown function each 3-5 sec, even though the
endTime
data doesn't change. I do like this:

function populate()
{

var url = apiurl + 'api/myGreatData';
$.ajax
({
type: 'POST',
cache: false,
url: url,
dataType: 'json',
success: function (response)
{
var source = document.getElementById("helloTmpl").innerHTML;

var tmpl= Handlebars.compile(source);

var html = tmpl(response);

var box = document.getElementById("box");

box.innerHTML = html;

// Countdown Timer
$('[data-countdown]').each(function (index, el) {
var $el = $(el);
var finalDate = $el.attr('data-countdown');

$el.countdown(finalDate, function (event) {
$(this).text(event.strftime('%D days %H:%M:%S'));
});
});

}
})
}


For some reason I feel it would be even greater if the countdown timer could be outside this
function populate()
with ajax, but then it wont work due to your DOM explanation. Perhaps the extra burden by calling countdown is too insignificant as well...

Answer

There's nothing difficult about what you are trying to do. The only rule is that you must make sure your endTime elements are added to the DOM before you invoke the plugin.

You need to add an HTML element into your template that the plugin will be bound to. Also, I don't know what endTime is since you did not include your data structure. I will assume a simpler data structure - an array of end time strings:

var endTimes = [
    '2017/01/01',
    '2018/02/02',
    '2019/03/03'
];

We will need a way to obtain each countdown element's final date for when we invoke the plugin. I will make this possible by adding a data-attribute, data-countdown, to the element in the template:

<script type="mustache/x.tmpl" id="helloTmpl">
    {{#each this}}
        <div data-countdown="{{.}}"></div>
    {{/each}}
</script>

Once we have added all of our countdown elements to the DOM, we are ready to invoke the plugin. We will loop over each element with a data-countdown attribute, get the finalDate value from this attribute, and then invoke the plugin for that element:

var template = Handlebars.compile($('#helloTmpl').html());
$('#Container').html(template(endTimes));

$('[data-countdown]').each(function (index, el) {
    var $el = $(el);
    var finalDate = $el.attr('data-countdown');

    $el.countdown(finalDate, function (event) {
        $(this).text(event.strftime('%D days %H:%M:%S'));
    });
});

Here is an example in a fiddle.