Внедрение задержки на $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;
});
});
Ответы
Ответ 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);
});