Мы видели как создать счетчик на AngularJS, который мы увеличивали или уменьшали с помощью нажатий на кнопку. В этом примере мы будем автоматически увеличивать счетчик с течением времени.
Не забудьте ознакомиться с другими примерами счетчиков!
Планирование будущего выполнения, используя $timeout
examples/angular/automatic_counter.html
<script src="angular.min.js"></script>
<script>
angular.module('CounterApp', [])
.controller('CounterController', function($scope, $timeout) {
$scope.counter = 0;
var updateCounter = function() {
$scope.counter++;
$timeout(updateCounter, 1000);
};
updateCounter();
});
</script>
<div ng-app="CounterApp">
<div ng-controller="CounterController">
{{counter}}
</div>
</div>
В этом примере функция контроллера ожидает два параметра. $scope
- содержит атрибуты, с которыми
мы взаимодействуем в нашем HTML, и $timeout
- это функция, похожая на setTimeout
из обычного Javascript.
(На самом деле это называется внедрение зависимости, а не параметры, но пока не будем беспокоиться об этом.
Особенно, пока я сам этого не понимаю.)
$timeout
это функция, которая принимает два параметра: функцию обратного вызова (коллбек) и время,
определенное в милисекундах.
Она откладывает выполнение полученной функции до истечения заданного времени. Если передать 1000 в качестве
второго параметра, мы отложим выполнение переданной функции на 1 секунду после того,
как собственно вызовем саму эту функцию.
Внутри функции контроллера первое что мы делаем, это создаем атрибут counter
и
устанавливаем ему значение по умолчанию 0. Мы хотим, чтобы отчет начинался с 0.
Затем мы создаем функцию updateCounter
, которая при вызове будет увеличивать counter
и использовать $timeout
,
чтобы вызвать себя же спустя 1 секунду. Это значит, что каждый раз при вызове функции updateCounter
она увеличит
счетчик и запланирует в системе повторный вызов через 1 секунду. Это значит, функция будет запускаться каждую секунду.
Затем последний шаг это первый вызов updateCounter
для запуска бесконечного цикла.
Счетчик с кнопкой Стоп
Этот счетчик будет увеличиваться каждую секунду, но что если мы захотим остановить его? Мы увидим пример с дополнительной кнопкой, которая остановит счетчик.
$timeout
возвращает объект promise
, который мы можем использовать позднее, чтобы отключить таймер.
Чтобы сделать promise
доступным, когда нам будет нужно, я создал переменную timer
и присвоил ей то, что вернула функция $timeout
.
(Конечно, я мог бы использовать здесь любое другое имя.)
Затем я добавил кнопку в HTML и указал в атрибуте ng-click
вызов метода stopCounter
.
Осталось сделать только метод stopCounter
.
Для начала я создал его, используя var stopCounter = function() { ... }
как и updateCounter
, но это не сработало. Так как мы хотим вызывать метод из HTML,
нам нужно добавить этот метод в $scope
. Следовательно, я должен был заменить
определение на:
$scope.stopCounter = function() { ... }
.
Внутри у нас есть выражение $timeout.cancel(timer);
, которое отменит работу таймера. Попробуйте!
examples/angular/automatic_counter_with_stop.html
<script src="angular.min.js"></script>
<script>
angular.module('CounterApp', [])
.controller('CounterController', function($scope, $timeout) {
var timer;
$scope.counter = 0;
$scope.stopCounter = function() {
$timeout.cancel(timer);
};
var updateCounter = function() {
$scope.counter++;
timer = $timeout(updateCounter, 1000);
};
updateCounter();
});
</script>
<div ng-app="CounterApp">
<div ng-controller="CounterController">
{{counter}}
<button ng-click="stopCounter()">Stop</button>
</div>
</div>
Счетчик с кнопками запуска и остановки
Еще одна штука, которую я хочу показать, это как я добавил еще одну кнопку для запуска счетчика дальше.
Первая версия была простой. Я просто добавил кнопку и новую функцию:
$scope.startCounter = function() {
updateCounter();
};
Проблема такого решения в том, что оно позволяло мне нажать несколько раз на кнопку старта,
и счетчик начинал увеличиваться слишком быстро, перескакивая иногда на 2 или 3 шага.
В реальности происходило вот что: каждый раз, когда я нажимал на кнопку start
, запускался
новый таймер и несколько таймеров работало параллельно.
Я должен был как-то убедиться, что в одно время работает только один таймер. Либо заблокировать
кнопку start
после нажатия, либо проверять, что таймер уже запущен, и запускать новый только если это не так.
Я выбрал это решение, так как был больше заинтересован в решении на JavaScript/AngularJS.
Я сделал два изменения. В функции stopCounter
я добавил
timer = null;
В конце концов все что у нас есть, это отмененный таймер, и нет смысла держать неиспользуемые объекты.
Затем в методе startCounter
я смог проверить, является ли timer
null
или нет,
и создать новый объект $timeout, если таймер отсутствует.
examples/angular/automatic_counter_with_stop_start.html
<script src="angular.min.js"></script>
<script>
angular.module('CounterApp', [])
.controller('CounterController', function($scope, $timeout) {
var timer;
$scope.counter = 0;
$scope.stopCounter = function() {
$timeout.cancel(timer);
timer = null;
};
$scope.startCounter = function() {
if (timer === null) {
updateCounter();
}
};
var updateCounter = function() {
$scope.counter++;
timer = $timeout(updateCounter, 1000);
};
updateCounter();
});
</script>
<div ng-app="CounterApp">
<div ng-controller="CounterController">
{{counter}}
<button ng-click="stopCounter()">Stop</button>
<button ng-click="startCounter()">Start</button>
</div>
</div>