4

I'm trying to call a function after a short delay after a user stops typing, but clearTimeout() does not seem to be doing what I think. The following is inside an Angular JS controller.

$scope.typing = false;
$scope.delay = undefined;

//Triggered by ng-keydown...
$scope.startTyping = function() {
    $scope.typing = true;
            console.log('start1', $scope.delay); //6
    clearTimeout( $scope.delay );
            console.log('start2', $scope.delay); //6... NOT getting cleared!
}

//Triggered by ng-keyup...
$scope.stopTyping = function() {
    $scope.typing = false;
    $scope.delay = setTimeout( $scope.lookup, 1000);
}

$scope.lookup = function() {

    if ($scope.typing === true){
        return false;
    }
    console.log('lookup'); //This fires after every key!

I see lookup in the logs for every key, instead of after every delay. Why is this?

Update

After logging the value of delay it is clear that clearTimeout() is not reseting the timer and instead, multiple timers are getting set and each one is triggering the lookup function.

For reference...

For anyone else troubleshooting clearTimeout(), here are some similar questions that may solve your problem (but didn't solve mine):

clearTimeout not working

clearTimeout() not working

clearTimeout is not working

clearTimeout not working

Community
  • 1
  • 1
emersonthis
  • 32,822
  • 59
  • 210
  • 375
  • Is it "lookupJobs" or just "lookup"? – Pointy Dec 23 '13 at 13:55
  • can you please show how `$scope.lookupJobs` is defined? also, this line seems odd: `$scope.delay;`. That is not a valid command, either remove it or do something like `$scope.delay = undefined;` – Dennis Dec 23 '13 at 13:55
  • `keydown` event happens after `keyup` event. Whereas you're trying to `cleatTimeout` an `undefined` variable. – Praveen Dec 23 '13 at 13:56
  • @Pointy Sorry that was a copy/paste error. – emersonthis Dec 23 '13 at 13:57
  • @PraveenJeganathan are you saying the `keydown` event is triggered *after* `keyup` when a key is pressed? Or on the subsequent key press? – emersonthis Dec 23 '13 at 13:58
  • Well those timer handles are just numbers; you should inject some `console.log()` calls to verify that the timer value set when you start the timer is the same one used to stop it. – Pointy Dec 23 '13 at 13:59
  • @Chips_100 I initialized `$scope.delay` as you advised. – emersonthis Dec 23 '13 at 14:00
  • Could not reproduce (http://jsfiddle.net/TN6zA/), but I'm using DOM `keyup`/`keydown` listeners; the event mechanisms you're using (Angular?) may vary. – apsillers Dec 23 '13 at 14:01
  • @apsillers Good point. Perhaps `ng-keyup` / `ng-keydown` dont't work quite the same. – emersonthis Dec 23 '13 at 14:03
  • @Pointy Can you clarify your last comment. I don't quite follow what you are advising me to log. – emersonthis Dec 23 '13 at 14:04
  • @SDP I'm advising you to log the value of `$scope.delay` after you call `setTimeout()` and *before* you try to use it with `clearTimeout()`. That will confirm that the value of `$scope.delay` is (or is not) being corrupted somehow. – Pointy Dec 23 '13 at 14:07
  • @Pointy I added `console.log($scope.delay);` after the `clearTimeout()` and it appears to be continuing. It should be 0 or undefined I think, but it's a an int like `6`. – emersonthis Dec 23 '13 at 14:08
  • @SDP that's what timer handles look like - they're just numbers, as if the browser simply keeps a "timer counter" somewhere internally. – Pointy Dec 23 '13 at 14:16
  • Sorry, did you check my jsfiddle? could you give me some feedback please? – coma Dec 23 '13 at 14:21

2 Answers2

3

http://jsfiddle.net/coma/y52Q2/1/

Controller

app.controller('Main', function ($scope) {

    var delay;

    var lookup = function() {

        console.log($scope.input);
    };

    $scope.lookup = function() {

        clearTimeout(delay);
        delay = setTimeout(lookup, 1000);
    };
});

View

<div ng-controller="Main">
    <input ng-model="input" ng-change="lookup()"/>
</div>

The problem with the up/down attemp is that stopTyping gets called more times than startTyping:

http://jsfiddle.net/coma/5hFjY/1/

coma
  • 16,429
  • 4
  • 51
  • 76
  • Is there a reason why you refactored it to user `ng-change()`? The code I posted here is a bit simplified, so it would take me some work to do it this way. I can do it, but it would help to understand what problem this is solving. – emersonthis Dec 23 '13 at 14:52
  • I refactored it to work off of `ng-change()` and it works now. But I would still love to understand why my original version didn't work. – emersonthis Dec 23 '13 at 15:35
  • I'm not 100% sure it's related to this specific aspect, but my code is throwing errors in FireFox (PC or Mac). I've posted a separate question here: http://stackoverflow.com/questions/20766636/angular-js-interpolation-error-in-firefox – emersonthis Dec 24 '13 at 20:56
  • I had faced that error too and the answers you've got are right, Chrome doesn't implement the standard js Date and supports more date string formats than Firefox. You should parse the string first or if you'll need more date calculation just try momentjs (it rocks). – coma Dec 25 '13 at 10:27
1

I would do like this : http://jsfiddle.net/TN6zA/2/

$scope = {};

    //on keydown...
    document.getElementById("foo").onkeydown = function() {    
        clearTimeout( $scope.delay );
        $scope.delay = setTimeout( $scope.lookup, 1000);
        document.getElementById("myDiv").innerHTML = "Someone is typing";
    }

    $scope.lookup = function() {
        document.getElementById("myDiv").innerHTML = "Nobody is typing";
    }

    $scope.lookup();
sdespont
  • 13,915
  • 9
  • 56
  • 97