Je suis nouveau sur AngularJS et j’ai un problème de performance que je n’arrive pas à résoudre. J’ai une recherche instantanée mais c’est un peu en retard, car il commence à chercher sur chaque keyup ().
JS:
var App = angular.module('App', []); App.controller('DisplayController', function($scope, $http) { $http.get('data.json').then(function(result){ $scope.ensortinges = result.data; }); });
HTML:
{{entry.content}}
Les données JSON ne sont même pas si grandes, 300 Ko seulement. Je pense que je dois mettre un délai d’environ 1 seconde sur la recherche pour attendre que l’utilisateur ait fini de taper, au lieu d’effectuer l’action à chaque frappe. AngularJS le fait en interne et après avoir lu des documents et d’autres sujets ici, je n’ai pas trouvé de réponse spécifique.
J’apprécierais des conseils sur la façon dont je peux retarder la recherche instantanée. Merci.
(Voir la réponse ci-dessous pour une solution Angular 1.3.)
Le problème ici est que la recherche sera exécutée chaque fois que le modèle change, ce qui correspond à chaque action de saisie sur une entrée.
Il y aurait des façons plus propres de faire cela, mais le moyen le plus simple serait probablement de changer la liaison pour que vous ayez une propriété $ scope définie dans votre Controller sur laquelle fonctionne votre filtre. De cette façon, vous pouvez contrôler la fréquence de mise à jour de cette variable $ scope. Quelque chose comme ça:
JS:
var App = angular.module('App', []); App.controller('DisplayController', function($scope, $http, $timeout) { $http.get('data.json').then(function(result){ $scope.ensortinges = 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:
{{entry.content}}
METTRE À JOUR
Maintenant, c’est plus facile que jamais (Angular 1.3), ajoutez simplement une option anti-rebond sur le modèle.
Mise à jour du plunker:
http://plnkr.co/edit/4V13gK
Documentation sur ngModelOptions:
https://docs.angularjs.org/api/ng/directive/ngModelOptions
Ancienne méthode:
Voici une autre méthode sans dépendances au-delà de l’angle.
Vous devez définir un délai d’expiration et comparer votre chaîne actuelle à la version antérieure, si les deux sont identiques, la recherche est effectuée.
$scope.$watch('searchStr', function (tmpStr) { if (!tmpStr || tmpStr.length == 0) return 0; $timeout(function() { // if searchStr is still the same.. // go ahead and resortingeve the data if (tmpStr === $scope.searchStr) { $http.get('//echo.jsontest.com/res/'+ tmpStr).success(function(data) { // update the textarea $scope.responseData = data.res; }); } }, 1000); });
et cela entre dans votre vue:
Le plunker obligatoire: http://plnkr.co/dAPmwf
En angular 1.3 je ferais ceci:
HTML:
Manette:
$scope.$watch('variableName', function(nVal, oVal) { if (nVal !== oVal) { myDebouncedFunction(); } });
Fondamentalement, vous indiquez à angular pour exécuter myDebounceFunction (), lorsque la variable de scope msg change. L’atsortingbut ng-model-options = “{debounce: 1000}” s’assure que msg ne peut être mis à jour qu’une fois par seconde.
Maintenant, nous pouvons régler les options du modèle de ng avec le temps et, lorsque le flou survient, le modèle doit être modifié immédiatement, sinon il aura une valeur plus ancienne si le délai n’est pas terminé.
Les mises à jour des modèles pour angularjs: http://jsfiddle.net/lgersman/vPsGb/3/
Dans votre cas, il n’ya rien de plus à faire que d’utiliser la directive dans le code jsfiddle comme ceci:
C’est essentiellement un petit morceau de code composé d’une seule directive angular nommée “ng-ampere-debounce” utilisant http://benalman.com/projects/jquery-throttle-debounce-plugin/ qui peut être attachée à n’importe quel élément dom. La directive réorganise les gestionnaires d’événements attachés afin qu’elle puisse contrôler le moment où limiter les événements.
Vous pouvez l’utiliser pour la limitation / le rebond * des mises à jour angulars du modèle * le gestionnaire d’événements angulars ng- [événement] * les gestionnaires d’événements jquery
Regardez: http://jsfiddle.net/lgersman/vPsGb/3/
La directive fera partie du cadre Orangevolt Ampere ( https://github.com/lgersman/jquery.orangevolt-ampere ).
Pour ceux qui utilisent le keyup / keydown dans le balisage HTML. Cela n’utilise pas la montre.
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
Comme introduit dans Angular 1.3
vous pouvez utiliser l’atsortingbut ng-model-options :
Je crois que la meilleure façon de résoudre ce problème est d’utiliser le plug-in / debounce du plugin jQuery de Ben Alman. A mon avis, il n’est pas nécessaire de retarder les événements de chaque champ de votre formulaire.
Enveloppez simplement votre fonction de gestion $ scope. $ Dans $ .debounce comme ceci:
$scope.$watch("searchText", $.debounce(1000, function() { console.log($scope.searchText); }), true);
Une autre solution consiste à append une fonctionnalité de délai pour modéliser la mise à jour. La directive simple semble faire un tour:
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); }); } }; });
Usage:
Donc, vous utilisez simplement le delayed-model
à la place du ng-model
et définissez le data-delay
souhaité.
J’ai résolu ce problème avec une directive qui consiste essentiellement à lier le modèle ng réel sur un atsortingbut spécial que je surveille dans la directive, puis à utiliser mon service de directive pour mettre à jour mon atsortingbut directive. il se lie au modèle anti-rebond au lieu du modèle ng.
.directive('debounceDelay', function ($comstack, $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 $comstack won't run it again! $comstack(element)(scope); } }; });
Usage:
Et dans le contrôleur:
$scope.search = ""; $scope.$watch('search', function (newVal, oldVal) { if(newVal === oldVal){ return; }else{ //do something meaningful }
Démo dans jsfiddle: http://jsfiddle.net/6K7Kd/37/
Le service $ debounce peut être trouvé ici: http://jsfiddle.net/Warspawn/6K7Kd/
Inspiré par la directive ultimateBind http://jsfiddle.net/fctZH/12/
Angular 1.3 aura une possibilité de rebond pour ng-model-options, mais jusque-là, vous devez utiliser une timer, comme l’a dit Josue Ibarra. Cependant, dans son code, il lance une timer à chaque pression sur une touche. En outre, il utilise setTimeout, quand dans Angular, il faut utiliser $ timeout ou utiliser $ apply à la fin de setTimeout.
Pourquoi tout le monde veut utiliser watch? Vous pouvez également utiliser une fonction:
var tempArticleSearchTerm; $scope.lookupArticle = function (val) { tempArticleSearchTerm = val; $timeout(function () { if (val == tempArticleSearchTerm) { //function you want to execute after 250ms, if the value as changed } }, 250); };
Je pense que le moyen le plus simple est de précharger le fichier json ou de le charger une fois sur $dirty
, puis la recherche de filtre se chargera du rest. Cela vous permettra d’économiser les appels http supplémentaires et de les rendre beaucoup plus rapides avec les données préchargées. La mémoire va faire mal, mais ça en vaut la peine.