2

I have a cross platform app developed using AngularJS and Onsen/Monaca UI.

I have a function that watches for changes on button clicks and if a certain number of clicks have been detected on a button, the user is taken to a confirmation screen.

However, if the user takes too long to select the buttons, they should be re-directed to another screen (not yet defined).

I am trying to implement the $timeout function with this but I cant seem to cancel the $timeout once the user has selected the buttons the right number of times. If the user select the buttons in the allowed time, they are taken to the confirmation page, but then the $timeout message is still displayed after 10 seconds.

Below is my implementation. It can be assumed that everything works - except the $timeout.cancel() in the stop() function.

// Initialise
var timer;

// Watch for changes on button clicks
$scope.$watch('currentAction', function(newValue, oldValue) {
    if (counter == 6) {
        // User clicked buttons - cancel the timer
        stop();
        // Segue to next page
        Segue.goTo("confirmation.html");
    }
    else {
        // Start the timer
        timer = $timeout(function () {
            alert("You are taking too long to respond");
        }, 10000);
    }
});

// Cancel the $timeout
function stop() {
    $timeout.cancel(timer);
}

Where the Segue.goTo() simply segues the user to the passed in page (unrelated but included for clarity)

var myFunctions = {
    goTo: function (url) {
        var nextPage = url;
        var element = document.querySelector("ons-navigator");
        var scope = angular.element(element).scope();
        scope.myNavigator.pushPage(nextPage);
    },
}
heyred
  • 2,031
  • 8
  • 44
  • 89

2 Answers2

2

you are creating timer in $scope.$watch, if the timer is created multiple times and kept with only one variable, you can only cancel the latest one by $timeout(timer). So the solution should be moving $timeout part out of $scope.$watch or keeping timers in an array and loop the array to stop them.

And if you still persist using in $scope.$watch, you shall cancel the previous one before creating new one.

if (timer) {
    $timeout.cancel(timer);
}
timer = $timeout(function () {
    alert("You are taking too long to respond");
}, 10000);

refer the below code snippet.

  • the timer is created once angular ends render the page.
  • the timer will be created once the test is changed.

angular.module("app", [])
  .controller("myCtrl", function($scope, $timeout) {
    var timer;
    $scope.$watch('test', function(newValue, oldValue) {
      console.log('$timeout created. value:' + newValue);
      timer = $timeout(function() {
        console.log('$timeout fired. value:' + newValue);
      }, 5000);
    })
    
    $scope.clickEvt = function() {
      console.log('$timeout canceld. currentValue:' + $scope.test);
      $timeout.cancel(timer);
    }
  })
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="myCtrl">
  <input type="text" ng-model="test">
  <button ng-click="clickEvt()">Stop<button>
</div>
Pengyy
  • 37,383
  • 15
  • 83
  • 73
0

try to use this

$timeout.cancel(timer);

but you need to define timer before the if

Fadi Abo Msalam
  • 6,739
  • 2
  • 20
  • 25
  • Tried that previous and still didnt cancel the $timeout. The $timeut message was still displayed regardless. – heyred May 08 '17 at 10:05
  • @heyred you are initialize timeouts in all other clicks.its not yet canceled.the only time out canceled is that the one you created at last.so you have to explicitly cancel other timeout to. cancel timeout in the begining of else clause do the trick i think. – zabusa May 08 '17 at 10:29
  • can you make sure the timer object in the if state is the same as in the else condition ?? and if so please pass the timer to the function stop as parameter – Fadi Abo Msalam May 08 '17 at 11:52