Функция автовызова в Durandaljs или Knockoutjs

У меня есть приложение, которое отображает относительное время активности с помощью плагина moment js. Время обновляется автоматически, сравнивая его с текущим временем и отображает (например, новостную ленту facebook). Приложение было ранее написано на angularjs, где я создал эту функциональность со следующим кодом:
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>

Фильтры angularjs вызываются автоматически каждую секунду, поэтому время обновляется, и мне не нужно об этом заботиться.

Теперь приложение переписывается, и js framework переходит с angularjs на durandaljs (по требованию клиента). Я не знаю, как мне добиться того же с durandaljs.


person Code Prank    schedule 11.12.2014    source источник
comment
Приложение Angular стало приложением Durandal, это интересно..   -  person Dziamid    schedule 13.12.2014
comment
Может ли Activity быть представлением? Вы говорите о множестве действий в одном из ваших комментариев. Являются ли действия просто объектными литералами с несколькими свойствами или чем-то более формальным? Вопрос немного вращается вокруг архитектуры. Создаем ли мы общий относительный таймер или конкретно относительный таймер активности? Кроме того, вы можете рассмотреть подход с глобальным таймером при разработке этого модуля. См. этот вопрос SO stackoverflow.com/q/2698866/3174746.   -  person    schedule 16.12.2014
comment
@EricTaylor Цель приложения — отслеживать время, затрачиваемое на действия разными людьми, поэтому у меня есть список действий, и каждое действие имеет свои свойства. Мне нужен конкретно таймер относительной активности, потому что пользователь также может приостанавливать и возобновлять таймер   -  person Code Prank    schedule 17.12.2014


Ответы (2)


Представления в durandal имеют жизненный цикл, поэтому вы можете использовать события для запуска (когда представление активирован) и остановить (когда представление деактивировано) таймер javascript. Добавьте в свою модель наблюдаемую ko с именем time_spent_trigger. Добавьте еще один ko вычисляемый наблюдаемый объект с именем time_spent_formatted, который выполняет все ваши расчеты момента и возвращает окончательный результат, но в верхней части сделайте так, чтобы он каким-то образом ссылался на time_spent_trigger. С вашей точки зрения, привяжите свойство time_spent_formatted вместо свойства time_spent. В событии активации запустите таймер, который обновляет time_spent_trigger каждую секунду. В событии деактивации отмените этот таймер. обновление значения для time_spent_trigger приведет к изменению и обновлению вычисляемого наблюдаемого в представлении.

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>
person Frank    schedule 11.12.2014
comment
Это представление будет просачиваться. Вам нужно добавить обработчик detached, который также является частью жизненного цикла представления, со следующей строкой: vm.time_spent_formatted.dispose(). Если вы не используете новый pureComputed, если он действительно может быть использован, вы должны избавиться от своих вычислений. - person ; 16.12.2014
comment
@EricTaylor интересно, не понимал этого, так что мне все равно нужно было бы выполнять удаление, если бы это был не синглтон (вместо того, чтобы возвращать vm, возвращать функцию для создания объекта vm)? - person Frank; 16.12.2014
comment
Тем более в несинглтонном случае. - person ; 17.12.2014

Итак, вам в основном нужен относительный таймер, верно?

Нам нужен кто-то, чтобы сказать нам, какое сейчас время.

//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;
});

Как здесь ваш относительный таймер, который использует события часов.

//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
    }

});
person Dziamid    schedule 13.12.2014
comment
На самом деле у меня есть массив активных действий, поэтому мне нужно обновить свойство time_spent каждого индекса в массиве, как я могу это сделать. Я новичок в Дюрандале. - person Code Prank; 15.12.2014
comment
Затем вы можете просто сделать timer.js фабрикой и создать по одному экземпляру для каждого элемента в вашем массиве. - person Dziamid; 16.12.2014