0

I developed a re-usable AngularJS service that allows the user to start, stop, and re-set a countdown timer from a view by clicking on buttons in the view. The re-usable service can be accessed through any controller that includes it. The working code for the minimal example countdown app can be viewed by clicking the link to this plnkr.

But I want the timer to be re-set to its max default value every time a user moves the mouse anywhere in the browser window. This means adding $window.addEventListener(...) somewhere in the service because the service has to be re-usable across any controller, while also responding to any movement of the mouse anywhere over the browser window, even the areas not contained within an HTML element linked to a controller. Thus, I cannot simply resort to adding ng-mousemove="somemethod()" in the html body tag the way this other example does. I would also prefer to avoid the $rootScope.broadcast approach taken by this other posting because I would like to keep the code isolated in the service as much as possible.

What specific changes need to be made to the code below so that the timer will be re-set to its default value any time the user moves the mouse anywhere in the browser window?

Though all of the code is in the plnkr for easy editing, I am also including it here.

index.html is:

<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Timer</title>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>

    <script src="myTimer.js" type="text/javascript"></script>
    <script src="exampleController.js" type="text/javascript"></script>
    <script src="app.js" type="text/javascript"></script>
</head>
<body ng-app="intervalExample">

<div>
  <div ng-controller="ExampleController">
    Test variable: {{ mytimer.testvariable }}<br>

    Time Remaining : <font color='red'>{{mytimer.timeleft}}</font>
    <br>
    <button type="button" data-ng-click="mytimer.startCountdown()">Start Countdown</button>
    <button type="button" data-ng-click="mytimer.stopCountdown()">Stop Countdown</button>
    <button type="button" data-ng-click="mytimer.resetCountdown()">Reset Timer</button>
  </div>
</div>
</body>
</html>

app.js is:

angular.('intervalExample',['ExampleController']);

exampleController.js is:

angular
.module('ExampleController', ['mytimer'])
.controller('ExampleController', ['$scope', 'mytimer', function($scope, mytimer) {

    $scope.mytimer = mytimer;
}]);

myTimer.js is:

angular
.module('mytimer', [])
.service('mytimer', ['$rootScope', '$interval', function($rootScope, $interval) {

    var $this = this;
    this.testvariable = "some value. ";

        this.timeleft = 15;

        var stop;
        this.startCountdown = function() {
          // Don't start a new countdown if we are already counting down
          if ( angular.isDefined(stop) ) return;

          stop = $interval(function() {
            if ($this.timeleft > 0 ) {
              $this.timeleft = $this.timeleft - 1;
            } else {
              $this.stopCountdown();
            }
         }, 1000);
        };

        this.stopCountdown = function() {
          if (angular.isDefined(stop)) {
            $interval.cancel(stop);
            stop = undefined;
          }
        };

        this.resetCountdown = function() {
          this.timeleft = 15;
        };

//        this.$on('$destroy', function() {
            // Make sure that the interval is destroyed too
//            $this.stopCountdown();
//        });

          function subsFunc() {
            $window.addEventListener('mousemove', function(e) {
            $this.timeleft = 15;
        })
  }

}]);
Community
  • 1
  • 1
CodeMed
  • 9,527
  • 70
  • 212
  • 364
  • Sounds like a perfect case for a directive to do the start/stops. Why do all that controller injection and repeated code? Same for timer display...use a directive – charlietfl Feb 24 '16 at 02:05

1 Answers1

1

Issues to consider:

  1. You are never calling subsFunc() and when you do will see that $window is not injected in service

  2. You will need to debounce the mousemove callback since the event triggers about every pixel. Resetting your timer every pixel makes no sense and would cause significant needless digests.

  3. Use of directive for buttons would negate needing to inject in numerous controllers

  4. Same for timer display ... can be directive and depending on UI combined with buttons

Community
  • 1
  • 1
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • Well really not clear what you are looking for then. You know the function needs to be called already to do the reset – charlietfl Feb 24 '16 at 02:47
  • It will if you inject `$window` and call the function ... but that gets down to issue of needing debounce also. Add a debounce to it ...lots of available code all over the web for doing it. – charlietfl Feb 24 '16 at 02:50
  • simply put `subsFunc();` in service. Remember that services are singletons so will activate once per whole page load – charlietfl Feb 24 '16 at 02:51
  • So did you try it @CodeMed? Works fine fixing injection and calling the function. But is heavy on digests without debounce – charlietfl Feb 24 '16 at 02:59