简体   繁体   中英

AngularJS - Fire $timeout event on ng-change only once

I have an ng-change on an input field in html that's bound to a scope variable.

<input type="text" ng-model="test" ng-change="change()" required>

var change = function(){ redraw_graph()}

Now when I change the input box, it redraws the graph for every new character I write. I want to have a delay (N seconds), so angular will wait before the user is done typing before the ng-change event fires. And if there are multiple ng-change events fired, it cancels the earlier ones and only executes the latest ones.

I've incorporated the delay with a timeout, but after N seconds the ng-change event still fires more than once. I've solved this problem before, but I can't figure out how to do it currently.

To me it seems like what you're asking for is already built into AngularJS. Thus, if you make use of the the ngModelOptions directive you can use the debounce property:

ng-model-options="{ debounce: 1000 }"

To quote the docs

.."/or 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."


Working sample

  angular.module('optionsExample', []) .controller('ExampleController', ['$scope', function($scope) { $scope.user = { name: 'say' }; } ]); 
 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Example - example-ngModelOptions-directive-debounce-production</title> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.5/angular.min.js"></script> <script src="app.js"></script> </head> <body ng-app="optionsExample"> <div ng-controller="ExampleController"> <form name="userForm"> Name: <input type="text" name="userName" ng-model="user.name" 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> </div> </body> </html> 

Based on @Blackhole's suggestion, you can work this out by cancelling your original $timeout.

Here is how you would do it:

var timer;

$scope.change = function(){
   $timeout.cancel( timer );

   timer = $timeout(function() {
             redraw_graph()
           },2000);
 }

Check below plunker to see how it works. An alert box (only one) will popup 2 seconds after you are done with all your changes on the input field. That is, if you change the input field before 2 seconds, you delay the popup by another 2 seconds.

http://plnkr.co/edit/v08RYwCDVtymNrgs48QZ?p=preview

EDIT
While above is one method of doing it, AngularJS has come up with its own implementation for this particular feature in v1.3+. ngModelOptions can be used.

你可能会看看.debounce() ,它有.debounce().throttle()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM