Reputation: 4250
I have an app which displays the activity relative time using moment js plugin. The time is refreshed automatically comparing it with current time and displays (like facebook newsfeed). App was previously written in angularjs where i built this functionality with following code:
JS:
filter('convertSeconds', function() {
return function(seconds) {
if( typeof(seconds) == 'undefined' ) return;
// units is a string with possible values of y, M, w, d, h, m, s, ms
var duration = moment.utc().subtract(seconds, 'seconds'), format = "";
if( duration.day() > 0 ) { format += "DD [days] "; }
if(duration.hour() > 0){ format += "H [hours] "; }
if(duration.minute() > 0){ format += "m [minutes] "; }
format += " s [seconds]";
return duration.fromNow(true);
}
}).
HTML:
<div class="time-spent">
<i class="fa fa-clock-o mrs fa-2"></i>
{{me.current.activity.time_spent|convertSeconds}}
</div>
The angularjs filters are called automatically every second therefore time is refreshed and i dont have to take care of that.
Now the app is being rewritten and js framework shifts from angularjs to durandaljs (on clients requirement) i dont know how can i achieve same thing with durandaljs.
Upvotes: 0
Views: 211
Reputation: 11581
So you basically need a relative timer, right?
We need someone to tell us what current time is.
//clock.js
define(function (require) {
var
events = require('durandal/events'),
moment = require('moment'),
clock = {};
events.includeIn(clock);
setInterval(function () {
clock.trigger('time:changed', moment());
}, 1000);
return clock;
});
How here is your relative timer that uses clock events.
//timer.js
define(function (require) {
var
ko = require('knockout'),
moment = require('moment'),
startTime = ko.observable(null),
relativeTime = ko.observable(),
start = function () {
startTime(moment());
},
stop = function () {
startTime(null);
},
clock = require('clock');
clock.on('time:changed').then(function (time) {
startTime() && relativeTime(moment.duration(time, startTime()).humanize());
});
return {
relativeTime: relativeTime, //use data-bind="text: relativeTime"
start: start,
stop: stop
}
});
Upvotes: 1
Reputation: 2198
Views in durandal have a life cycle so you can use events to start(when the view is activated) and stop(when the view is deactivated) a javascript timer. Add a ko observable called time_spent_trigger to your model. Add another ko computed observable called time_spent_formatted that does all your moment calculations and returns the final result but at the top, make it reference the time_spent_trigger in some way. In your view, bind to the time_spent_formatted property instead of the time_spent property. In the activate event, start a timer that updates the time_spent_trigger every second. In the deactivate event, cancel this timer. updating the value for the time_spent_trigger will cause the computed observable to change and be updated on the view.
JS:
define([
'durandal/system',
'knockout'
],
function (system, ko) {
var vm = {
time_spent = ko.observable(),
time_spent_trigger = ko.observable(0),
activate: activate,
deactivate: deactivate,
updateTimerId = 0
};
vm.time_spent_formatted = ko.computed(function () {
//reference the trigger observable in some way
if (vm.time_spent_trigger() > 0)
{
//do your moment calculation and return here
return result_of_moment_calculation
} else {
return "Not Started";
}
}
return vm;
function activate() {
vm.updateTimerId = setInterval(function () {
vm.time_spent_trigger(vm.time_spent_trigger() + 1);
}, 10000);
}
function deactivate() {
clearInterval(vm.updateTimerId);
}
});
HTML:
<div class="time-spent">
<i class="fa fa-clock-o mrs fa-2"></i>
<span data-bind="text: time_spent_formatted"></span>
</div>
Upvotes: 1