-2

I have a piece of code as follows. It reacts to the change of the input field by running treat:

JSBin

<html ng-app="app">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
  </head>
  <body ng-controller="Ctrl">
    <input type="text" ng-model="text"></input>
    <div id="console"></div>
    <script>
      var app = angular.module('app', []);
      app.controller('Ctrl', ["$scope", function ($scope) {
        $scope.$watch('text', function (newValue, oldValue) {
          treat(newValue);
        }, false)
      }])

      function treat(x) {
        debug(x)
      }

      function debug(msg) {
        document.getElementById("console").innerHTML += msg + "<br/>";
      }
    </script>
  </body>
</html>

Now, I want to do something special: I want to set a minimal interval (say 500 ms) between 2 treat. So if another treat is supposed to run very shortly after a treat, I want it to wait a little bit; if the time interval between 2 treat is larger than 500 ms, they could run one after another as normal (I don't want to add a 500 ms on top of that).

Does anyone know how to achieve this?

SoftTimur
  • 5,630
  • 38
  • 140
  • 292
  • Possible duplicate of [Javascript: how to stop the click event queuing?](https://stackoverflow.com/questions/44289889/javascript-how-to-stop-the-click-event-queuing) – Jonas Wilms Jun 23 '17 at 17:24
  • ng-options can do that can't it? otherwise what you're describing is called a throttle, not a debounce. The initial action happens immediately, then any subsequent actions can't happen more than once per interval. – Kevin B Jun 23 '17 at 17:30

2 Answers2

0

Instead of using $watch use the ng-change directive and to throttle the number of calls to the treat function, use the debounce property of the ng-model-options directive:

<input type="text" name="userName"
       ng-model="user.name"
       ng-change="treat()"
       ng-model-options="{ debounce: 1000 }" />

The above example waits one second between updates of the model and calls to the treat function.

Debouncing model updates with ng-model-options

The debounce property allows you to specify a debouncing delay so that the actual update only takes place when a timer expires; this timer will be reset after another change takes place.

— AngularJS ng-model-options API Reference (Debouncing)

The DEMO

angular.module('optionsExample', [])
.controller('ExampleController', ['$scope', function($scope) {
  $scope.user = { name: 'say' };
  $scope.updates = 0;
  $scope.treat = function() {
    $scope.updates++;
  };
}]);
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="optionsExample">
    <div ng-controller="ExampleController">
  <form name="userForm">
    Name:
    <input type="text" name="userName"
           ng-model="user.name"
           ng-change="treat()"
           ng-model-options="{ debounce: 1000 }" />
    <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
  </form>
  <pre>user.name = <span ng-bind="user.name"></span></pre>
  <pre>Number of calls to treat() = {{updates}}</pre>
</div>
  </body>
Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Thank you... But I think I want to catch every single change, and just delay their corresponding `treat` if two `treat` are too close... – SoftTimur Jun 25 '17 at 12:36
  • I will leave this answer here for other readers who may find it useful. – georgeawg Jun 25 '17 at 13:39
-1

You could implement a qeue were one element is taken out and executed every 500ms :

var qeue=[];
function treat(x) {
   qeue.unshift(x);
}
setInterval(function(){
 if(qeue.length){
   debug(qeue.pop())
 }
},500);

If you want to stop if the qeue is empty:

var qeue=[];
function treat(x) {
   qeue.unshift(x);
}
(function next(){
 if(qeue.length){
   debug(qeue.pop());
   setTimeout(next,500);
 }else{
  qeue.unshift=function(x){
    qeue=[x];
    next();
   };
 }
})();
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151