Автоматический счетчик на AngularJS
Мы видели как создать счетчик на 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>Try!
В этом примере функция контроллера ожидает два параметра. $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>Try!
Счетчик с кнопками запуска и остановки
Еще одна штука, которую я хочу показать, это как я добавил еще одну кнопку для запуска счетчика дальше.
Первая версия была простой. Я просто добавил кнопку и новую функцию:
$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>Try!

Published on 2015-10-25