Programing

AngularJS 빠른 검색을 지연시키는 방법은 무엇입니까?

lottogame 2020. 6. 13. 10:14
반응형

AngularJS 빠른 검색을 지연시키는 방법은 무엇입니까?


해결할 수없는 성능 문제가 있습니다. 인스턴트 검색이 있지만 각에서 검색을 시작하기 때문에 다소 게으 릅니다 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>

JSON 데이터는 300KB 정도로 크지 않습니다. 필자가 달성해야 할 것은 각 키 입력에 대한 작업을 수행하는 대신 사용자가 입력을 마칠 때까지 검색을 ~ 1 초 지연시키는 것입니다. AngularJS는 내부적 으로이 작업을 수행하며 여기에서 문서 및 기타 주제를 읽은 후에는 구체적인 답변을 찾을 수 없었습니다.

인스턴트 검색을 지연시킬 수있는 방법에 대한 조언을 부탁드립니다.


(Angular 1.3 솔루션에 대해서는 아래 답변을 참조하십시오.)

여기서 문제는 모델이 변경 될 때마다 검색이 실행되며 입력에 대한 모든 키업 동작입니다.

이 작업을 수행하는 더 깨끗한 방법이 있지만 가장 쉬운 방법은 필터가 작동하는 컨트롤러 내부에 $ scope 속성이 정의되도록 바인딩을 전환하는 것입니다. 그렇게하면 $ scope 변수가 얼마나 자주 업데이트되는지 제어 할 수 있습니다. 이 같은:

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>

최신 정보

이제 그 어느 때보 다 쉬워졌습니다 (Angular 1.3). 모델에 디 바운스 옵션을 추가하기 만하면됩니다.

<input type="text" ng-model="searchStr" ng-model-options="{debounce: 1000}">

업데이트 된 플 런커 :
http://plnkr.co/edit/4V13gK

ngModelOptions에 대한 설명서 :
https://docs.angularjs.org/api/ng/directive/ngModelOptions

오래된 방법 :

각도 자체를 넘어 의존성이없는 또 다른 방법이 있습니다.

시간 초과를 설정하고 현재 문자열을 이전 버전과 비교해야합니다. 둘 다 동일하면 검색을 수행합니다.

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

그리고 이것은 당신의 견해에 들어갑니다 :

<input type="text" data-ng-model="searchStr">

<textarea> {{responseData}} </textarea>

필수 플 런커 : http://plnkr.co/dAPmwf


Angular 1.3에서 나는 이것을 할 것이다 :

HTML :

<input ng-model="msg" ng-model-options="{debounce: 1000}">

제어 장치:

$scope.$watch('variableName', function(nVal, oVal) {
    if (nVal !== oVal) {
        myDebouncedFunction();
    }
});

기본적으로 범위 변수가 변경 myDebouncedFunction()되면 angular에게 run을 지시합니다 msg. 이 속성을 ng-model-options="{debounce: 1000}"사용 msg하면 1 초에 한 번만 업데이트 할 수 있습니다.


 <input type="text"
    ng-model ="criteria.searchtext""  
    ng-model-options="{debounce: {'default': 1000, 'blur': 0}}"
    class="form-control" 
    placeholder="Search" >

이제 ng-model-options 디 바운스를 시간과 함께 설정할 수 있으며 블러, 즉시 모델을 변경해야 할 경우 저장하지 않으면 지연이 완료되지 않으면 더 오래된 값을 갖습니다.


HTML 마크 업에서 키업 / 키 다운을 사용하는 사람들을 위해. 시계를 사용하지 않습니다.

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...">

angularjs에 대한 디 바운스 / 스로틀 모델 업데이트 : http://jsfiddle.net/lgersman/vPsGb/3/

귀하의 경우 jsfiddle 코드에서 지시문을 다음과 같이 사용하는 것 외에는 할 일이 없습니다.

<input 
    id="searchText" 
    type="search" 
    placeholder="live search..." 
    ng-model="searchText" 
    ng-ampere-debounce
/>

Its basically a small piece of code consisting of a single angular directive named "ng-ampere-debounce" utilizing http://benalman.com/projects/jquery-throttle-debounce-plugin/ which can be attached to any dom element. The directive reorders the attached event handlers so that it can control when to throttle events.

You can use it for throttling/debouncing * model angular updates * angular event handler ng-[event] * jquery event handlers

Have a look : http://jsfiddle.net/lgersman/vPsGb/3/

The directive will be part of the Orangevolt Ampere framework (https://github.com/lgersman/jquery.orangevolt-ampere).


Just for users redirected here:

As introduced in Angular 1.3 you can use ng-model-options attribute:

<input 
       id="searchText" 
       type="search" 
       placeholder="live search..." 
       ng-model="searchText"
       ng-model-options="{ debounce: 250 }"
/>

I believe that the best way to solve this problem is by using Ben Alman's plugin jQuery throttle / debounce. In my opinion there is no need to delay the events of every single field in your form.

Just wrap your $scope.$watch handling function in $.debounce like this:

$scope.$watch("searchText", $.debounce(1000, function() {
    console.log($scope.searchText);
}), true);

Another solution is to add a delay functionality to model update. The simple directive seems to do a trick:

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:

<input delayed-model="searchText" data-delay="500" id="searchText" type="search" placeholder="live search..." />

So you just use delayed-model in place of ng-model and define desired data-delay.

Demo: http://plnkr.co/edit/OmB4C3jtUD2Wjq5kzTSU?p=preview


I solved this problem with a directive that basicly what it does is to bind the real ng-model on a special attribute which I watch in the directive, then using a debounce service I update my directive attribute, so the user watch on the variable that he bind to debounce-model instead of 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);
  }
};
});

Usage:

<input type="text" debounce-delay="1000" debounce-model="search"></input>

And in the controller :

    $scope.search = "";
    $scope.$watch('search', function (newVal, oldVal) {
      if(newVal === oldVal){
        return;
      }else{ //do something meaningful }

Demo in jsfiddle: http://jsfiddle.net/6K7Kd/37/

the $debounce service can be found here: http://jsfiddle.net/Warspawn/6K7Kd/

Inspired by eventuallyBind directive http://jsfiddle.net/fctZH/12/


Angular 1.3 will have ng-model-options debounce, but until then, you have to use a timer like Josue Ibarra said. However, in his code he launches a timer on every key press. Also, he is using setTimeout, when in Angular one has to use $timeout or use $apply at the end of setTimeout.


Why does everyone wants to use watch? You could also use a function:

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

I think the easiest way here is to preload the json or load it once on$dirty and then the filter search will take care of the rest. This'll save you the extra http calls and its much faster with preloaded data. Memory will hurt, but its worth it.

참고URL : https://stackoverflow.com/questions/15304562/how-to-put-a-delay-on-angularjs-instant-search

반응형