Implement a delay on $scope.$watch

前端 未结 5 1610
醉话见心
醉话见心 2021-02-07 03:33

I was wondering whether or not it is possible to implement a slight delay on $scope.$watch. I have the following which queries the server, so I\'d like to implement a slight del

相关标签:
5条回答
  • 2021-02-07 03:41

    you can use ng-model-option, if the model 'query' is a Html tag or Angular directive, for Ej:

    <input type ng-model="query" ng-model-options="{ updateOn: 'default blur', debounce: { 'default':
     2000, 'blur': 1 } }" />
    

    You can see the Angular Doc here: https://docs.angularjs.org/api/ng/directive/ngModelOptions

    0 讨论(0)
  • 2021-02-07 03:53

    You can use the current value of query to decide when you want to fire the call:

    $scope.$watch("query", function (value) {
    
        //implement rule here for value
        //example value is at least 3 characters
        if (value && value.length > 3) {
    
            $scope.loading = true;
            returnFactory.query($scope.query).then(function (returns) {
                $scope.returns = returns;
                $scope.loading = false;
            });
        }
    });
    
    0 讨论(0)
  • I like to use Lo-Dash which provides two really useful capabilities: debounce and throttle which does exactly what you want. Let's say you want to make sure it only calls the function once per 150 ms:

    function update() {
     $scope.loading = true;
        returnFactory.query($scope.query).then(function (returns) {
            $scope.returns = returns;
            $scope.loading = false;
        });
    }
    
    $scope.$watch("query", function () {
       _.throttle(update, 150);
    });
    

    The throttle function lets you control when the update function is called (trailing or leading edge).

    I use Lo-Dash all the time in my app. It is a must-have library for me... more useful than jQuery. But, you can create a custom build of Lo-Dash which only includes the throttle and debounce functions if you don't want to include the entire library.

    0 讨论(0)
  • 2021-02-07 03:59

    Just a snippet that I found useful for similar case:

    function watchWithDelay(scope, prop, callback, delayMs) {
      delayMs = delayMs || 1000;
      var lastTimeChanged = new Date();
      scope.$watch(prop, function(n, o) {
        lastTimeChanged = new Date();
        setTimeout(function() {
          var diff = new Date().getTime() - lastTimeChanged.getTime();
          if (diff < delayMs-100 || diff > delayMs+100) {
            return;
          }
          callback(n, o);
        }, delayMs);
      });
    }
    

    You can use it in a controller like this:

    watchWithDelay($scope, 'client.phone', function(n, o) {
      if (n === o) {
        return;
      }
      // any custom validations, for example
      if (!n) {
        return alert('Phone is required');
      }
      if (n.length < 11) {
        return alert('Phone is shorter than 11 digits');
      }
      // here I should save it somehow
      console.log('Phone is changed to ' + n);
    });
    
    0 讨论(0)
  • 2021-02-07 04:00

    Normally i'd say use angular's $timeout for this delay but you cant clear this timeout yet.

    //EDIT:you can.

    Set a timeout and clear it, if this watcher gets triggered fast enought.

    Like this:

    var timeoutCode;
    var delayInMs = 2000;
    $scope.$watch("query", function(query) {
     clearTimeout(timeoutCode);  //does nothing, if timeout alrdy done
     timeoutCode = setTimeout(function(){   //Set timeout
         $scope.loading = true;
         returnFactory.query(query).then(function(returns) {
           $scope.returns = returns;
           $scope.loading = false;
         });
     },delayInMs);
    });
    

    http://jsfiddle.net/4FuyY/

    UPDATE Thanks to stewie this can be achieved with angular's $timeout.

        var timeoutPromise;
        var delayInMs = 2000;
        $scope.$watch("query", function(query) {
         $timeout.cancel(timeoutPromise);  //does nothing, if timeout alrdy done
         timeoutPromise = $timeout(function(){   //Set timeout
             $scope.loading = true;
             returnFactory.query(query).then(function (returns) {
               $scope.returns = returns;
               $scope.loading = false;
             });
         },delayInMs);
        });
    
    0 讨论(0)
提交回复
热议问题