Подтвердить что ты не робот

Внедрение задержки на $scope. $Watch

Мне было интересно, возможно ли реализовать небольшую задержку в $scope. $watch. У меня есть следующее, которое запрашивает сервер, поэтому я хотел бы выполнить небольшую задержку, прежде чем оценивать query перед запросом сервера. Я заметил, что если вы быстро набираете текст, он запутывается и не отправляет правильную информацию:

$scope.$watch("query", function () {
    $scope.loading = true;
    returnFactory.query($scope.query).then(function (returns) {
        $scope.returns = returns;
        $scope.loading = false;
    });
});
4b9b3361

Ответ 1

Обычно я бы сказал, использую angular $timeout для этой задержки, но вы еще не можете очистить этот тайм-аут.

//EDIT: вы можете.

Установите тайм-аут и очистите его, если этот наблюдатель будет вызван достаточно быстро.

Вот так:

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/

ОБНОВЛЕНИЕ Благодаря stewie это может быть достигнуто с помощью angular $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);
    });

Ответ 2

вы можете использовать опцию ng-model, если модель "запрос" является тегом Html или директивой Angular, для Ej:

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

Вы можете увидеть Angular Doc здесь: https://docs.angularjs.org/api/ng/directive/ngModelOptions

Ответ 3

Мне нравится использовать Lo-Dash, который предоставляет две действительно полезные возможности: debounce и throttle, который делает именно то, что вы хотите. Скажем, вы хотите удостовериться, что он вызывает функцию только один раз за 150 мс:

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);
});

Функция throttle позволяет вам управлять при вызове функции update (задний или передний край).

Я использую Lo-Dash все время в своем приложении. Это обязательная библиотека для меня... более полезна, чем jQuery. Но вы можете создать пользовательскую сборку Lo-Dash, которая включает только функции throttle и debounce, если вы не хотите включать всю библиотеку.

Ответ 4

Вы можете использовать текущее значение query, чтобы решить, когда вы хотите запустить вызов:

$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;
        });
    }
});

Ответ 5

Просто фрагмент, который я нашел полезным для подобного случая:

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);
  });
}

Вы можете использовать его в контроллере следующим образом:

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);
});