1

I was developing a simple stopwatch app using AngularJS + Angular Material + Electron, and somehow the data changes/watches were being delayed, until another UI interaction takes place (?) This had never happened before when I was using Bootstrap, and I can confirm it is not Electron that is the issue.

As I'm starting out today with these, I've made use of latest versions of AngularJS, Angular Material and Electron, all pulled with Bower.

EDIT: Here's the pen: http://codepen.io/anon/pen/jWgzev

Here's where the app starts:

start

Upon pressing the play button, the timer starts counting down to zero, and the play button gets replaced:

then

And when the timer hits zero, the button should have been replaced by an orange stop button, and yet it does not happen:

enter image description here

And when you hover your mouse over one of the two buttons on screen, the gray button magically transforms to orange:

enter image description here

I apologize in advance if I'm posting blocks of code, I just don't know where the problem is.

HTML:

<!doctype html>
<html class="no-js" lang="" ng-app="breaktime-stopwatch">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="apple-touch-icon" href="apple-touch-icon.png">

        <link rel="stylesheet" href="styles/normalize.min.css">
        <link rel="stylesheet" href="styles/main.css">
        <link rel="stylesheet" href="styles/font-awesome.min.css">
        <link href="./bower_components/angular-material/angular-material.css" rel="stylesheet" />
        <link rel="stylesheet" href="styles/app.css">

        <!--<script src="scripts/vendor/modernizr-2.8.3.min.js"></script>-->
        <script>
            window.nodeRequire = require;
            delete window.require;
            delete window.exports;
            delete window.module;
        </script>
    </head>
    <body ng-controller="AppController as vm" layout="column">
        <md-toolbar layout="row">
            <div class="md-toolbar-tools">
                <span>
                    <h1 class="md-title">Breaktime Stopwatch</h1>
                </span>
                <!-- fill up the space between left and right area -->
                <span flex></span>
                <md-button href="" class="md-icon-button">
                    <md-icon md-font-icon='fa fa-question-circle fa-2x'></md-icon>
                    <md-tooltip md-direction="left">
                        About and Help
                    </md-tooltip>
                </md-button>
            </div>
        </md-toolbar>
        <md-content layout="column" layout-padding>
            <div flex layout="row" layout-align="center center">
                <!--<md-progress-circular md-mode="indeterminate" md-diameter="50"></md-progress-circular>-->
                <!--<md-progress-circular md-mode="determinate" ng-value="meter" md-diameter="50"></md-progress-circular>-->
                <timer class="clock md-display-4" autostart="false" interval="1000" countdown="break_duration" finish-callback="stopTimer()">{{minutes}}:{{seconds}}</timer>

            </div>
            <div layout="row" layout-align="center center">
                <span ng-if="playButton">
                    <md-button class="md-fab md-primary" aria-label="Play" ng-click="startTimer()">
                        <md-icon md-font-icon='fa fa-play fa-2x'></md-icon>
                        <md-tooltip md-direction="top">
                            Start
                        </md-tooltip>
                    </md-button>
                </span>
                <span ng-if="stopEarlyButton">
                    <md-button class="md-fab md-accent" aria-label="Stop Earlier" ng-click="stopEarlyTimer()">
                        <md-icon md-font-icon='fa fa-stop fa-2x'></md-icon>
                        <md-tooltip md-direction="top">
                            Stop
                        </md-tooltip>
                    </md-button>
                </span>
                <span ng-if="stopButton">
                    <md-button class="md-fab md-warn"  aria-label="Stop" ng-click="stopTimer()">
                        <md-icon md-font-icon='fa fa-exclamation fa-2x'></md-icon>
                        <md-tooltip md-direction="top">
                            Stop
                        </md-tooltip>
                    </md-button>
                </span>
            </div>
        </md-content>





        <!--[if lt IE 8]>
            <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
        <![endif]-->
        <!--pre-dependencies-->

        <script src="scripts/plugins.js"></script>
        <!--dependencies-->
        <script src="./bower_components/jquery/dist/jquery.min.js" type="text/javascript" ></script>        
        <script src="./bower_components/angular/angular.js" type="text/javascript" ></script>
        <script src="./bower_components/angular-animate/angular-animate.js" type="text/javascript" ></script>
        <script src="./bower_components/angular-aria/angular-aria.js" type="text/javascript" ></script>
        <script src="./bower_components/angular-material/angular-material.js" type="text/javascript" ></script>
        <script src="./bower_components/momentjs/min/moment.min.js" type="text/javascript" ></script>
        <!--<script src="./bower_components/momentjs/min/locales.min.js" type="text/javascript" ></script>-->
        <script src="./bower_components/humanize-duration/humanize-duration.js" type="text/javascript" ></script>
        <script src="./bower_components/angular-timer/dist/angular-timer.min.js" type="text/javascript" ></script>
        <!--application config-->
        <script src="scripts/app.js"></script>
        <!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
        <!--<script>
            (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=
            function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;
            e=o.createElement(i);r=o.getElementsByTagName(i)[0];
            e.src='//www.google-analytics.com/analytics.js';
            r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
            ga('create','UA-XXXXX-X','auto');ga('send','pageview');
        </script>-->
    </body>
</html>

JS:

(function () { 

    'use strict'; 

    var btsw = angular.module('breaktime-stopwatch', [
        'ngMaterial',
        'timer'
    ]);

    btsw.config(function($mdThemingProvider) {
        $mdThemingProvider.theme('default')
            .primaryPalette('indigo')
            .accentPalette('grey');
    });

    btsw.controller('AppController', function AppController($scope, $mdDialog){
        $scope.timerRunning = false;
        $scope.playButton = true;
        $scope.stopEarlyButton = false;
        $scope.stopButton = false;
        $scope.break_duration = 10; 
        $scope.break_var = angular.copy($scope.break_duration);
        // $scope.meter = 0;

        $scope.startTimer = function (){
            $scope.$broadcast('timer-start');
            $scope.timerRunning = true;
            $scope.playButton = false;
            $scope.stopEarlyButton = true;
        };

        $scope.stopEarlyTimer = function (){
            $scope.$broadcast('timer-stop');
            $scope.timerRunning = false;
            $scope.playButton = true;
            $scope.stopEarlyButton = false;
        };

        $scope.stopTimer = function (){
            $scope.stopEarlyButton = false;
            $scope.$broadcast('timer-stop');
            $scope.timerRunning = false;
            $scope.playButton = false;
            $scope.stopEarlyButton = false;
            $scope.stopButton = true;
        };

        $scope.test = function(){
            console.log($scope.break_duration);
            console.log($scope.break_var);
            // console.log($scope.meter);
        }

        $scope.$on('timer-tick', function (event, data) {
                $scope.break_var = data.millis/1000;

                // if($scope.meter < Math.round(100-(($scope.break_var/$scope.break_duration)*100)))
                // {$scope.meter = Math.round(100-(($scope.break_var/$scope.break_duration)*100));}
                // console.log($scope.meter);
        });

    });
})();

Any kind of help that will point me to the right direction will be greatly appreciated!

Ralph Sto. Domingo
  • 398
  • 1
  • 2
  • 13

1 Answers1

1

Without digging into the timer code too much, I'm guessing that the finish-callback functionality that it provides may be running at the end of the digest loop, or entirely outside of Angular's digest cycle (which is a bit odd since it's an Angular module).

If this is the case, simply adding $scope.$digest(); to the end of your $scope.stopTimer() function should do the trick.

Here is an updated Codepen which works as expected: http://codepen.io/topherfangio/pen/bEXXNj

EDIT: As a side-note: it changes in your Codepen after hovering the button because the tooltip is triggering a digest cycle.

Topher Fangio
  • 20,372
  • 15
  • 61
  • 94