Jak opóźnić AngularJS instant search?
Jestem nowy w AngularJS i mam problem z wydajnością, którego nie mogę rozwiązać. Mam natychmiastowe wyszukiwanie, ale jest nieco opóźnione, ponieważ zaczyna szukać na każdym keyup ().
JS:
var App = angular.module('App', []);
App.controller('DisplayController', function($scope, $http) {
$http.get('data.json').then(function(result){
$scope.entries = result.data;
});
});
HTML:
<input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />
<div class="entry" ng-repeat="entry in entries | filter:searchText">
<span>{{entry.content}}</span>
</div>
Dane JSON nie są nawet tak duże, tylko 300KB, myślę, że to, co muszę osiągnąć, to umieścić opóźnienie ~1 SEK na wyszukiwaniu, aby czekać na użytkownika, aby zakończyć pisanie, zamiast wykonywania akcji na każdym naciśnięciu klawisza. AngularJS robi to wewnętrznie, a po czytając dokumenty i inne tematy nie mogłem znaleźć konkretnej odpowiedzi.
Będę wdzięczny za wszelkie wskazówki, jak Mogę opóźnić natychmiastowe wyszukiwanie. Dzięki.12 answers
(Zobacz odpowiedź poniżej dla rozwiązania kątowego 1.3.)
Problem polega na tym, że wyszukiwanie będzie wykonywane za każdym razem, gdy zmieni się model, czyli każda akcja keyup na wejściu.
Byłyby czystsze sposoby na to, ale prawdopodobnie najprostszym sposobem byłoby przełączenie wiązania tak, aby mieć właściwość $ scope zdefiniowaną wewnątrz kontrolera, na którym działa filtr. W ten sposób możesz kontrolować częstotliwość aktualizacji zmiennej $scope. Coś jak to:
JS:
var App = angular.module('App', []);
App.controller('DisplayController', function($scope, $http, $timeout) {
$http.get('data.json').then(function(result){
$scope.entries = result.data;
});
// This is what you will bind the filter to
$scope.filterText = '';
// Instantiate these variables outside the watch
var tempFilterText = '',
filterTextTimeout;
$scope.$watch('searchText', function (val) {
if (filterTextTimeout) $timeout.cancel(filterTextTimeout);
tempFilterText = val;
filterTextTimeout = $timeout(function() {
$scope.filterText = tempFilterText;
}, 250); // delay 250 ms
})
});
HTML:
<input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />
<div class="entry" ng-repeat="entry in entries | filter:filterText">
<span>{{entry.content}}</span>
</div>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-25 07:29:04
UPDATE
Teraz jest to łatwiejsze niż kiedykolwiek (Angular 1.3), wystarczy dodać opcję debounce w modelu.
<input type="text" ng-model="searchStr" ng-model-options="{debounce: 1000}">
Updated plunker:
http://plnkr.co/edit/4V13gK
Dokumentacja dotycząca ngModelOptions:
https://docs.angularjs.org/api/ng/directive/ngModelOptions
Stara metoda:
Oto kolejna metoda bez zależności poza samym kanałem.
Musisz ustawić timeout i porównać swój bieżący string z poprzednią wersją, jeśli obie są takie same, to wykonuje wyszukiwanie.
$scope.$watch('searchStr', function (tmpStr)
{
if (!tmpStr || tmpStr.length == 0)
return 0;
$timeout(function() {
// if searchStr is still the same..
// go ahead and retrieve the data
if (tmpStr === $scope.searchStr)
{
$http.get('//echo.jsontest.com/res/'+ tmpStr).success(function(data) {
// update the textarea
$scope.responseData = data.res;
});
}
}, 1000);
});
I to idzie do twojej opinii:
<input type="text" data-ng-model="searchStr">
<textarea> {{responseData}} </textarea>
Obowiązkowy plunker: http://plnkr.co/dAPmwf
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-26 01:21:13
W Angular 1.3 zrobiłbym tak:
HTML:
<input ng-model="msg" ng-model-options="{debounce: 1000}">
Kontroler:
$scope.$watch('variableName', function(nVal, oVal) {
if (nVal !== oVal) {
myDebouncedFunction();
}
});
W zasadzie każesz angular uruchomić mydebouncedfunction (), gdy zmienna zakresu MSG się zmieni. Atrybut ng-model-options= "{debounce: 1000} " sprawia, że msg może aktualizować tylko raz na sekundę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-27 11:45:24
<input type="text"
ng-model ="criteria.searchtext""
ng-model-options="{debounce: {'default': 1000, 'blur': 0}}"
class="form-control"
placeholder="Search" >
Teraz możemy ustawić ng-model-options debounce z czasem i kiedy blur, model musi zostać natychmiast zmieniony, w przeciwnym razie przy zapisie będzie miał starszą wartość, jeśli opóźnienie nie zostanie zakończone.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-14 14:50:32
Debuted / throttled model updates for angularjs : http://jsfiddle.net/lgersman/vPsGb/3/
W Twoim przypadku nie ma nic więcej do zrobienia niż użycie dyrektywy w kodzie jsfiddle w następujący sposób:
<input
id="searchText"
type="search"
placeholder="live search..."
ng-model="searchText"
ng-ampere-debounce
/>
To w zasadzie mały fragment kodu składający się z pojedynczej dyrektywy kątowej o nazwie "ng-ampere-debounce" wykorzystującej http://benalman.com/projects/jquery-throttle-debounce-plugin / , który może być dołączony do dowolnego elementu dom. Dyrektywa zmienia kolejność załączonych obsługa zdarzeń, dzięki czemu może kontrolować, kiedy należy Dławić zdarzenia.
Możesz go użyć do dławienia/debouncingu * aktualizacje kątowe modelu * angular event handler ng-[event] * obsługa zdarzeń jquery
Zobacz: http://jsfiddle.net/lgersman/vPsGb/3/
Dyrektywa będzie częścią ram Orangevolt Ampere ( https://github.com/lgersman/jquery.orangevolt-ampere).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-15 13:14:43
Dla tych, którzy używają keyup/keydown w znacznikach HTML. To nie używa zegarka.
JS
app.controller('SearchCtrl', function ($scope, $http, $timeout) {
var promise = '';
$scope.search = function() {
if(promise){
$timeout.cancel(promise);
}
promise = $timeout(function() {
//ajax call goes here..
},2000);
};
});
HTML
<input type="search" autocomplete="off" ng-model="keywords" ng-keyup="search()" placeholder="Search...">
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-16 07:20:02
Tylko dla użytkowników przekierowanych tutaj:
Jak wprowadzono w Angular 1.3
możesz użyć ng-model-options atrybut:
<input
id="searchText"
type="search"
placeholder="live search..."
ng-model="searchText"
ng-model-options="{ debounce: 250 }"
/>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-22 05:08:07
Uważam, że najlepszym sposobem rozwiązania tego problemu jest użycie wtyczki Ben Alman jQuery throttle / debounce. Moim zdaniem nie ma potrzeby opóźniania zdarzeń z każdego pola w formularzu.
Po prostu zapakuj swój $ scope.$funkcja obsługi zegarka w $.debounce tak:
$scope.$watch("searchText", $.debounce(1000, function() {
console.log($scope.searchText);
}), true);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-28 20:16:24
Innym rozwiązaniem jest dodanie funkcji opóźnienia do aktualizacji modelu. Prosta dyrektywa wydaje się robić sztuczkę:
app.directive('delayedModel', function() {
return {
scope: {
model: '=delayedModel'
},
link: function(scope, element, attrs) {
element.val(scope.model);
scope.$watch('model', function(newVal, oldVal) {
if (newVal !== oldVal) {
element.val(scope.model);
}
});
var timeout;
element.on('keyup paste search', function() {
clearTimeout(timeout);
timeout = setTimeout(function() {
scope.model = element[0].value;
element.val(scope.model);
scope.$apply();
}, attrs.delay || 500);
});
}
};
});
Użycie:
<input delayed-model="searchText" data-delay="500" id="searchText" type="search" placeholder="live search..." />
Więc wystarczy użyć delayed-model
zamiast ng-model
i zdefiniować pożądane data-delay
.
Demo: http://plnkr.co/edit/OmB4C3jtUD2Wjq5kzTSU?p=preview
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-07 09:02:26
Rozwiązałem ten problem za pomocą dyrektywy, która zasadniczo polega na powiązaniu prawdziwego modelu ng ze specjalnym atrybutem, który Oglądam w dyrektywie, a następnie za pomocą usługi debounce aktualizuję atrybut dyrektywy, więc użytkownik obserwuje zmienną, którą wiąże z debounce-model zamiast ng-model.
.directive('debounceDelay', function ($compile, $debounce) {
return {
replace: false,
scope: {
debounceModel: '='
},
link: function (scope, element, attr) {
var delay= attr.debounceDelay;
var applyFunc = function () {
scope.debounceModel = scope.model;
}
scope.model = scope.debounceModel;
scope.$watch('model', function(){
$debounce(applyFunc, delay);
});
attr.$set('ngModel', 'model');
element.removeAttr('debounce-delay'); // so the next $compile won't run it again!
$compile(element)(scope);
}
};
});
Użycie:
<input type="text" debounce-delay="1000" debounce-model="search"></input>
I w kontrolerze:
$scope.search = "";
$scope.$watch('search', function (newVal, oldVal) {
if(newVal === oldVal){
return;
}else{ //do something meaningful }
Demo w jsfiddle: http://jsfiddle.net/6K7Kd/37/
Usługa $debounce można znaleźć tutaj: http://jsfiddle.net/Warspawn/6K7Kd/
Zainspirowany ostatecznie dyrektywą http://jsfiddle.net/fctZH/12/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 22:53:08
Angular 1.3 będzie miał debounce ng-model-options, ale do tego czasu musisz użyć timera, jak powiedział Josue Ibarra. Jednak w swoim kodzie uruchamia timer przy każdym naciśnięciu klawisza. Ponadto używa setTimeout, gdy w Angular trzeba użyć $timeout lub $apply na końcu setTimeout.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-25 15:45:10