Таймер обратного отсчета 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