Search code examples
javascriptangularjsintervalsangularjs-routingangularjs-factory

Taking actions on inactive page in angular


I'm new to AngularJS, coming from a jQuery background. At the moment I take my first steps and create some sample pages with Angular.

Now I wanted to achieve some thing like this: Think of an app with two "pages". First is the main page with some text etc and on the other theres running a timer. The timer should start from 0 and count up to infinite by every second, right when you started the app. This is the first thing I cannot achieve. My timer only starts when I navigate to the second page.

The second problem: When the timer is running, I want to navigate through all the pages in the app and the timer should still count in the background. Well, at the moment it does run in the background, but every time when I navigate to the page with the timer, it seems like there gets opened another task that count the timer up, resulting in a very infrequent and faster counting.

On my index html I use ng-view to insert the other pages by ngRoute. This works fine.

My timer page looks like this:

<div ng-controller="TimeCtrl">
    <p>Counter: {{counter.getValue()}}</p>
</div>

Then I wrote a timer controller for my app:

app.controller("TimeCtrl", function($scope, $interval, Counter){

    $scope.counter = Counter;

    $interval(function(){
        $scope.counter.update();
    }, 1000);
});

And there's a counter factory:

app.factory("Counter", function () {

    this.counter = 0;

    var self = this;

    return {
        update : function () {
            self.counter++;
        },
        getValue : function () {
            return self.counter;
        }
    }
});

I would appreciate any help as Angular does not come that easy for me in the beginning.


Solution

  • Instead of using the $interval on the controller, use it on the service/factory:

    app.factory("Counter", function ($interval) {
        this.counter = 0;
        var self = this;
    
        $interval(function(){
            self.update();
        }, 1000);  
    
        return {
            update : function () {
                self.counter++;
            },
            getValue : function () {
                return self.counter;
            }
        }
    });
    

    This way if your TimeCtrl gets destroyed (for whatever reason), the counter will still get incremented.

    Note also that every time you re-open a page that creates a new TimeCtrl, a new interval will also be defined. That's why you are getting that "infrequent and faster counting".

    Regarding it being loaded only on the second page, make sure that you add the Counter service as dependency to your main controller, so that the service gets instantiated immediately (otherwise the counter will not start). If you do not have a main controller, use a run block:

    app.run(function(Counter) {
      // just inject the Counter so that it gets instantiated
    })