angularJS таймер за обратно отброяване в низходящ ред

var app = angular.module('quizApp', []);

app.directive('timer', function($timeout, $compile) {
  return {
    restrict: 'E',
    replace: false,
    scope: {
      interval: '=interval',
      startTimeAttr: '=startTime',
      countdownattr: '=countdown'
    },
    controller: function($scope, $element) {
      if ($element.html().trim().length === 0) {
        $element.append($compile('<span>{{millis}}</span>')($scope));
      }

      $scope.startTime = null;
      $scope.timeoutId = null;
      $scope.countdown = $scope.countdownattr && parseInt($scope.countdownattr, 10) > 0 ? parseInt($scope.countdownattr, 10) : undefined;
      $scope.isRunning = false;

      $scope.$on('timer-start', function() {
        $scope.start();
      });

      $scope.$on('timer-resume', function() {
        $scope.resume();
      });

      $scope.$on('timer-stop', function() {
        $scope.stop();
      });

      function resetTimeout() {
        if ($scope.timeoutId) {
          clearTimeout($scope.timeoutId);
        }
      }

      $scope.start = $element[0].start = function() {
        $scope.startTime = $scope.startTimeAttr ? new Date($scope.startTimeAttr) : new Date();
        resetTimeout();
        tick();
      };

      $scope.resume = $element[0].resume = function() {
        resetTimeout();
        $scope.startTime = new Date() - ($scope.stoppedTime - $scope.startTime);
        tick();
      };

      $scope.stop = $element[0].stop = function() {
        $scope.stoppedTime = new Date();
        resetTimeout();
        $scope.timeoutId = null;
      };

      $element.bind('$destroy', function() {
        resetTimeout();
      });

      var tick = function() {
        if ($scope.countdown > 0) {
          $scope.countdown--;
        } else if ($scope.countdown <= 0) {
          $scope.stop();
        }

        $scope.millis = new Date() - $scope.startTime;

        if ($scope.countdown > 0) {
          $scope.millis = $scope.countdown * 1000
        }

        $scope.seconds = Math.floor(($scope.millis / 1000) % 60);
        $scope.minutes = Math.floor((($scope.millis / (1000 * 60)) % 60));
        $scope.hours = Math.floor((($scope.millis / (1000 * 60 * 60)) % 24));
        $scope.days = Math.floor((($scope.millis / (1000 * 60 * 60)) / 24));

        //We are not using $timeout for a reason. Please read here - https://github.com/siddii/angular-timer/pull/5

        console.log($scope.seconds)
        $scope.timeoutId = setTimeout(function() {
          tick();
          $scope.$apply();
        }, $scope.interval);

        $scope.$emit('timer-tick', {
          timeoutId: $scope.timeoutId,
          millis: $scope.millis
        });
      };

      $scope.start();
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="quizApp">
  <timer interval="1000">Time ends in : {{hours}} hours, {{minutes}} minutes, {{seconds}} seconds</timer>
</div>

Имам тази директива за таймер и имам някои проблеми, изброени по-долу. Не можах да го разбера. Всяка помощ ще бъде оценена.

1) часовете, минутите и секундите не се актуализират в маркирането.

2) таймерът е в нарастващ ред. Искам го в низходящ ред.

Използвам този таймер в моето приложение за тестове. Да кажем, че общото време е 1 час 54 минути 00 секунди. При стартиране на теста таймерът трябва да започне да намалява със секунди и след това минути и след това часове. Когато стане 0, трябва да получа предупреждение.

Благодаря ви предварително.


person Community    schedule 01.09.2017    source източник
comment
Работя върху отговор. За какво се отнася $scope.countdown? Текущото оставащо време?   -  person kauffee000    schedule 01.09.2017


Отговори (1)


Няколко проблема, които виждам:

  1. Имате два незадължителни атрибута, дефинирани в обхвата на вашата директива, но те не се предават в HTML директивата за таймер.
  2. Причината вашите HTML стойности да не се попълват е, че тези стойности не са обвързани с обхвата на директивата. Вие сте задали изолиран обхват, когато сте преминали през тези атрибути към директивата. Ако са обвързани с директивата, бих ги добавил като шаблон.
  3. Няма начин да се определи къде започва таймерът. Това е добър кандидат за предаване на променлива.
  4. Използване на функция за контролер вместо връзка линк срещу контролер
  5. Не бях сигурен какво прави кодът за милисекунди, така че просто го показах на брояча, ако съществува. Чувствайте се свободни да го направите, както искате.
  6. Не бях сигурен какво прави $emit, но предполагам, че го използва някакъв друг код. Ако не, можете да го премахнете.
  7. Превключих към използване на интервал от таймаут, защото създаваше много таймаути, но никога не ги спираше. Например, всеки цикъл прави нов timeoutId, така че ако се опитате да го спрете, той просто спира последния цикъл.

var app = angular.module('app', []);

app.directive('timer', function($timeout, $compile) {
  return {
restrict: 'E',
scope: {
  interval: '=', //don't need to write word again, if property name matches HTML attribute name
  startTimeAttr: '=?startTime', //a question mark makes it optional
  countdownAttr: '=?countdown' //what unit?
},
template: '<div><p>'+
  '<p>Time ends in : {{ hours }} hour<span data-ng-show="hours > 1">s</span>, ' +
  '{{ minutes }} minutes, ' +
  '{{ seconds }} seconds ' +
  '<span data-ng-if="millis">, milliseconds: {{millis}}</span></p>' +

  '<p>Interval ID: {{ intervalId  }}<br>' +
  'Start Time: {{ startTime | date:"mediumTime" }}<br>' +
  'Stopped Time: {{ stoppedTime || "Not stopped" }}</p>' +
  '</p>' +
  '<button data-ng-click="resume()" data-ng-disabled="!stoppedTime">Resume</button>' +
  '<button data-ng-click="stop()" data-ng-disabled="stoppedTime">Stop</button>',

link: function (scope, elem, attrs) {

  //Properties
  scope.startTime = scope.startTimeAttr ? new Date(scope.startTimeAttr) : new Date();
  var countdown = (scope.countdownAttr && parseInt(scope.countdownAttr, 10) > 0) ? parseInt(scope.countdownAttr, 10) : 60; //defaults to 60 seconds
  
  function tick () {
    
    //How many milliseconds have passed: current time - start time
    scope.millis = new Date() - scope.startTime;
    
    if (countdown > 0) {
      scope.millis = countdown * 1000;
      countdown--;
    } else if (countdown <= 0) {
      scope.stop();
      console.log('Your time is up!');
    }

    scope.seconds = Math.floor((scope.millis / 1000) % 60);
    scope.minutes = Math.floor(((scope.millis / (1000 * 60)) % 60));
    scope.hours = Math.floor(((scope.millis / (1000 * 60 * 60)) % 24));
    scope.days = Math.floor(((scope.millis / (1000 * 60 * 60)) / 24));

    //is this necessary? is there another piece of unposted code using this?
    scope.$emit('timer-tick', {
      intervalId: scope.intervalId,
      millis: scope.millis
    });
    
    scope.$apply();
    
  }
  
  function resetInterval () {
    if (scope.intervalId) {
      clearInterval(scope.intervalId);
      scope.intervalId = null;
    }        
  }
  
  scope.stop = function () {
    scope.stoppedTime = new Date();
    resetInterval();
  }
  
  //if not used anywhere, make it a regular function so you don't pollute the scope
  function start () {
    resetInterval();
    scope.intervalId = setInterval(tick, scope.interval);           
  }
  
  scope.resume = function () {
    scope.stoppedTime = null;
    scope.startTime = new Date() - (scope.stoppedTime - scope.startTime);
    start();
  }
  
  start(); //start timer automatically
  
  //Watches
  scope.$on('time-start', function () {
    start();
  });
  
  scope.$on('timer-resume', function() {
    scope.resume();
  });
  
  scope.$on('timer-stop', function() {
    scope.stop();
  });
  
  //Cleanup
  elem.on('$destroy', function () {
    resetInterval();
  });
  
}
  };
});
<!DOCTYPE html>
<html data-ng-app="app">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>

 <timer interval="1000" countdown="61"></timer>
 
</body>
</html>

Или работещ JSBin тук.

person kauffee000    schedule 01.09.2017
comment
Благодаря за отделеното време и усилия.. Ще прегледам този отговор.. Стискам палци! - person ; 05.09.2017
comment
възможно ли е да се обвърже countdown=61 с променлива на обхвата - person Shahid Neermunda; 03.10.2018