最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Angular js ng-change event - Stack Overflow

programmeradmin0浏览0评论

I am using angular js in my application. where in ng-change event i am calling webservice and based on the response rendering the html. but here in ng-change calls too frequently where we type fastly which causes browser to wait. this is not a problem in chrome and mozilla. can anyone help me here?

I am using angular js in my application. where in ng-change event i am calling webservice and based on the response rendering the html. but here in ng-change calls too frequently where we type fastly which causes browser to wait. this is not a problem in chrome and mozilla. can anyone help me here?

Share Improve this question asked Apr 7, 2014 at 5:34 KamalKamal 411 silver badge3 bronze badges 1
  • Make sure you have not use {{}} in the ng-change event. stackoverflow.com/questions/17785617/… – Fizer Khan Commented Apr 7, 2014 at 5:45
Add a comment  | 

6 Answers 6

Reset to default 6

You could use a timeout and wait for the user to have finished typing before making a call to the server:

<input type="text" ng-model="some.thing" ng-change="fetchData()" />

app.controller('someCtrl', function ($scope, $timeout) {
    var fetchDataDelay = 500;   // milliseconds
    var fetchDataTimer;

    $scope.fetchData = function () {
        $timeout.cancel(fetchDataTimer);
        fetchDataTimer = $timeout(function () {
            // make expensive call to the server...
        }, fetchDataDelay);
    };
});

Note that using Angular's $timeout (instead of setTimeout/clearTimeout) will take care of the Angular digest cycle for you (so you don't have to bother yourself with manually calling $apply() or $digest()).

I also faced a similar problem, I wanted to implement a debounced search. After a bit of headbanging, this is what I did :

Here is my input field marked with ng-model directive

<input ng-model="searchText" ng-model-options="{ debounce: 500 }" type="text" class="form-control" placeholder="Search...">

Please observe that I also included an ng-model-options="{ debounce: 500 }". It debounces the update to the underlying model by the specified number of milliseconds. Please refer to the documentation for ng-model-options directive here.

Now, I added a $watch like this :

    $scope.$watch('searchText', function(newValue) {
        // expensive ajax call
    });

Please refer to the documentation of $watch here. It registers an event listener listening for any change in the expression passed as its first argument. In this case 'searchText', which is the model associated with my input field.

The debounce mentioned in the ng-model-options, debounces the update to the 'searchText' model and hence, it takes care of debouncing the ajax call(in my case).

Hope it helps. :)

You'll want to use a debounce pattern, along these lines:

.factory('myFactory', function($http) {
  var debounce;
  var doRequest = function() {
    clearTimeout(debounce);
    setTimeout(function() {
      // Make HTTP call here
    }, 333);
  };
  return {
    doRequest: doRequest
  };
});

What this does is send the request 333 milliseconds after the last time it's been called. If you're calling it on every change, this will add a little spacing between requests, optimizing the application.

333 is what Google uses for text input, feel free to play around with the values and see what works best for you.

You can use $watch or $watchCollection to achieve the live event.

In my understanding and usage $watch and $watchCollection is quiet efficient than ng-change.

Here is a good example,

$scope.$watchCollection('[some_modelname,someother_modelname]',function(){
            alert('Changed the input value!');
        });
$scope.$watch('some_modelname',function(){
            alert('Changed the input value!');
        });

Inside HTML,

<input type="text" ng-model="some_modelname" id="someid" name="somenameifneeded" value=""/>
<input type="text" ng-model="someother_modelname" id="someotherid" name="somenameifneeded" value=""/>

Both $watch and $watchCollection keep looking at the input field for any changes. Once made any changes the trigger will be called and this will keep never die.. Hope this helps.

on angularjs 1/3 you have the debounce as ng-options here is an example so you can add it to your ng-change and it will manage it for you

ng-model-options="{debounce: {'default': 500} }

You should use debounce approach - while you are typing too frequently the server should not bit hit. When you stop typing and timeout occurs the request should be sent to the server. You can either use Underscore Debounce feature or make a custom implementation here:

$scope.loadData = function () {
   var loadThrottle;
   clearTimeout(loadThrottle);
   loadThrottle = setTimeout(function () {
       $scope.$apply(function () {
           $scope.getData();
       });
   }, 500);
};

The request here will be sent only if you stop typing and 500ms timeout occurs after that.

Another implementation (using angularized approach):

$scope.loadData = function(timeout) {
     $scope.counter += 1;
     var counter = $scope.counter;
     $timeout(function(){
         if (counter === $scope.counter) {
             $scope.getData();
             $scope.counter = 0;
         }
     }, timeout ? timeout : 500);
}

And also alternative is using more generic approach with custom directive and Underscore something like that:

app.directive('changeTimeout', function() {
    return {
        require: 'ngModel',
        link: function(scope, element, attrs, ctrl) {
            angular.forEach(ctrl.$viewChangeListeners, function(listener, index) {
                ctrl.$viewChangeListeners[index] = _.debounce(function() {
                    scope.$apply(attrs.ngChange);
                }, attrs.changeTimeout || 0)
            });
        }
    }
});
发布评论

评论列表(0)

  1. 暂无评论