akcasoy
akcasoy

Reputation: 7225

Having an Angular $interval running independent of controller

I have different pages on may application which have their own controllers. One of them has an $interval function, let's say a timer. Click on a button will start this interval function, which updates itself every second. What i want to have is, i want to be able to go to any other page in my application (calling different controllers), but i want my interval to continue running until i stop it explicitly from the first controller. A rootScope interval so to speak. How can i do it?

EDIT: Thanks to Chris and Patrick i now have a simple Service, looks like this:

  .service('TimerService', function($interval) {
    var promise;
    var timerSeconds = 0;

    this.start = function () {
      promise = $interval(function () {
        timerSeconds++;
      }, 1000);
    };

    this.stop = function () {
      promise.cancel(interval);
      timerSeconds = 0;
    };

    this.getTimer = function() {
      return timerSeconds;
    }
  })

I store also my current value (timerSeconds) in this service. But how can i sync this value to my controller? The service increments the timerSeconds, and at the beginning of my controller i read it from this service through its getTimer() function, but it clearly will not be updated on my controller. How can i sync this service attribute with my local attribute?

EDIT:

when i define my service attribute as an object and the timerSeconds as number inside that object (it seems primitives cannot be synced):

var timer = {seconds : 0};

this.getTimer = function() {
  return timer;
}

and get this object from my controller through that getter:

vm.timer = TimerService.getTimer();

they are all in sync.

Upvotes: 1

Views: 1190

Answers (2)

Patrick
Patrick

Reputation: 6958

Don't bother adding it to $rootScope. Use a service that can be used anywhere in the app. Here is a singleton timer that can start and stop. Define the intervalTimeout in the service itself, or if you want to be really flexible, do so in a provider (probably overkill for this example).

angular.module('myApp', [])

.service('AppCallback', function ($interval) {
    var states = states = {
        PENDING: 0,
        STARTED: 1
    }, intervalTimeout = 3000, // Set this
    interval;

    this.states = states;
  
    this.state = states.PENDING;
    this.start = function (callback) {
        if (this.state !== states.PENDING) {
            return;
        }

        interval = $interval(callback, intervalTimeout);
        this.state = states.STARTED;
    }

    this.stop = function () {
        if (this.state !== states.STARTED) {
            return;
        }
        $interval.cancel(interval);
        this.state = states.PENDING;
    };
})

.controller('MainController', function ($scope, AppCallback) {
  var vm = {},
      count = 0;
  
  vm.toggle = function toggle() {
    if (AppCallback.state === AppCallback.states.PENDING) {
      AppCallback.start(function () {
        vm.data = 'Ticked ' + (++count) + ' times.';
      });
     } else {
       AppCallback.stop();
     }
  };
  
  
  $scope.vm = vm;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainController">
  {{vm.data}}
  <br />
  <button ng-click="vm.toggle()">Toggle</button>
</div>

Upvotes: 2

Chris
Chris

Reputation: 27394

If you want to share any data between controllers the correct way is to use a service.

I would then create a service that allows you to stop and start this timer / interval.

The initial controller would kick this off and it would continue to "tick" forever until it is stopped.

Upvotes: 2

Related Questions