AngularJS तत्काल खोज पर देरी कैसे करें?


147

मेरे पास एक प्रदर्शन समस्या है जिसे मैं संबोधित नहीं कर सकता। मेरे पास एक त्वरित खोज है लेकिन यह कुछ हद तक कम है, क्योंकि यह प्रत्येक पर खोज शुरू करता है keyup()

जे एस:

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 यह आंतरिक रूप से करता है, और डॉक्स और अन्य विषयों को पढ़ने के बाद यहां मुझे एक विशिष्ट उत्तर नहीं मिला।

मैं किसी भी संकेत की सराहना करूंगा कि मैं तत्काल खोज में देरी कैसे कर सकता हूं।


1
आपको init ऐप पर सभी json मिल रहे हैं ... और फिर आपके खोज फ़िल्टर को टाइप करने पर दूसरी बार डेटा नहीं मिल रहा है ... यह पहले से मौजूद मॉडल को फ़िल्टर कर रहा है। क्या मैं सही हूँ?
मैक्सिम

क्या नीचे दिए गए जवाब से काम चल गया? यदि हां, तो कृपया उत्तर स्वीकार करें। यदि नहीं, तो मुझे बताएं और मैं आगे स्पष्ट करूंगा।
जेसन एडेन

हे जेसन, प्रतिक्रिया के लिए धन्यवाद। मैं आपके कोड के साथ खेलने की कोशिश कर रहा था, लेकिन भाग्य नहीं, खोज मेरे लिए पूरी तरह से काम करना बंद कर देती है।
दिमागी

कोई बात नहीं, यह मेरा बुरा था जिसे मैंने कुछ अनदेखा किया। आपका समाधान वास्तव में काम करता है।
साभार

इस उत्तर पर एक नज़र डालें, जो एक निर्देश प्रदान करता है जो आपको एनजी-परिवर्तन में देरी करने की अनुमति देता है: stackoverflow.com/questions/21121460/…
डग

जवाबों:


121

(एक कोणीय 1.3 समाधान के लिए नीचे उत्तर देखें।)

यहाँ मुद्दा यह है कि खोज हर बार मॉडल में बदलाव करेगी, जो कि इनपुट पर हर कीअप क्रिया है।

ऐसा करने के लिए क्लीनर तरीके होंगे, लेकिन संभवत: सबसे आसान तरीका यह होगा कि आप बाइंडिंग स्विच कर सकते हैं ताकि आपके पास आपके नियंत्रक के अंदर एक $ स्कोप प्रॉपर्टी परिभाषित हो, जिस पर आपका फ़िल्टर काम करता है। इस तरह से आप नियंत्रित कर सकते हैं कि कितनी बार $ स्कोप वैरिएबल अपडेट किया गया है। कुछ इस तरह:

जे एस:

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>

ध्यान दें कि $ स्कोप। $ घड़ी एक कोणीय-यूआई बूटस्ट्रैप के मोडल केng-model अंदर काम नहीं करेगी
हेंडी इरावन

1
मुझे लगता है कि यह बिना tempFilterText वैरिएबल के भी काम करेगा: $ गुंजाइश। $ watch ('searchText', function (val) {if (filterTextTimeout) $ timeout.cancel (filterTextTimeout); filterTextTimeout = $ timeout (function () {$ गुंजाइश] FilterText = val;}, 250); // देरी 250 ms})
जोस ऑवेनवेन

@JosTheeuwen यह केवल एक वैश्विक चर है जिसे बुरा अभ्यास माना जाता है और इसे सख्त मोड में अनुमति नहीं दी जाती है
mb21

301

अपडेट करें

अब यह पहले से ज्यादा आसान है (कोणीय 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


2
मेरे लिए यह स्वीकृत की तुलना में बहुत अधिक समझने योग्य उत्तर है :) धन्यवाद!
ओज_

3
क्या ऐसा कोई मुद्दा नहीं है जहां कई मॉडल परिवर्तन हो सकते हैं, इस प्रकार डुप्लिकेट अनुरोधों के कारण? @ जेसनडेन के जवाब में, वह पहले से कतारबद्ध घटनाओं को रद्द करके इसका ध्यान रखता है।
ब्लेककोवेज़

सिद्धांत रूप में, यदि मॉडल परिवर्तन का अनुभव करता है, लेकिन डेटा समान रहता है, तो यह कई अनुरोधों का कारण होगा। व्यवहार में मैंने ऐसा कभी नहीं देखा। यदि आप चिंतित हैं तो आप उस किनारे के मामले की जांच के लिए एक ध्वज जोड़ सकते हैं।
जोस अलेक्जेंडर इबारा

यह अब तक कोणीय 1.3
मार्कस डब्ल्यू

यहां चेतावनी: यदि आपके पास एक कीपर ईवेंट है जो सबमिट या ट्रिगर्स करता है, तो यह नवीनतम मॉडल वैल्यू के बिना ऐसा करेगा क्योंकि वैल्यू बाइंडिंग की चर्चा की जाती है। उदाहरण के लिए 'फू' टाइप करें और तात्कालिक की-रिटर्न पर मान अभी भी एक खाली स्ट्रिंग होगा।
jbodily

34

कोणीय 1.3 में मैं यह करूंगा:

HTML:

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

नियंत्रक:

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

असल में आप कोणीय को चलाने के लिए कह रहे हैं myDebouncedFunction(), जब msgदायरा परिवर्तनशील होता है। विशेषता ng-model-options="{debounce: 1000}"यह सुनिश्चित करती है कि msgकेवल एक सेकंड में एक बार अपडेट हो सकता है।


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

अब हम समय के साथ एनजी-मॉडल-विकल्प की बहस को सेट कर सकते हैं और जब धुंधला हो जाता है, तो मॉडल को तुरंत बदलने की आवश्यकता होती है अन्यथा बचत पर यह पुराना मूल्य होगा यदि विलंब पूरा नहीं हुआ है।


9

HTML मार्कअप में की-अप / कीडाउन का उपयोग करने वालों के लिए। यह घड़ी का उपयोग नहीं करता है।

जे एस

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

एचटीएमएल

<input type="search" autocomplete="off" ng-model="keywords" ng-keyup="search()" placeholder="Search...">

6

एंगुलरज के लिए घोषित / थ्रॉटल किए गए मॉडल अपडेट: http://jsfiddle.net/lgersman/vPsG/3//

आपके मामले में इस तरह के jsfiddle कोड में निर्देश का उपयोग करने से ज्यादा कुछ नहीं है:

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

इसका मूल रूप से कोड का एक छोटा सा टुकड़ा है, जिसमें http://benalman.com/projects/jquery-throttle-debounce-plugin/ का उपयोग करके "एनजी-एम्पीयर-डेब्यूज़" नामक एकल कोणीय निर्देश शामिल है, जो किसी भी डोम तत्व से जुड़ा हो सकता है। निर्देश संलग्न घटना संचालकों को फिर से व्यवस्थित करता है ताकि यह थ्रॉटल घटनाओं को नियंत्रित कर सके।

आप इसे थ्रॉटलिंग / डिबॉन्डिंग के लिए उपयोग कर सकते हैं * मॉडल कोणीय अपडेट * कोणीय ईवेंट हैंडलर एनजी- [ईवेंट] * jquery ईवेंट हैंडलर

एक नज़र है: http://jsfiddle.net/lgersman/vPsGb/3/

निर्देश ऑरेंजवोल्ट एम्पीयर फ्रेमवर्क ( https://github.com/lgersman/jquery.orangevolt-ampere ) का हिस्सा होगा ।


6

उपयोगकर्ताओं के लिए यहां पुनर्निर्देशित किया गया है:

जैसा कि Angular 1.3आप शुरू में एनजी-मॉडल-विकल्प विशेषता का उपयोग कर सकते हैं :

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

5

मेरा मानना ​​है कि इस समस्या को हल करने का सबसे अच्छा तरीका है बेन अल्मन के प्लगइन jQuery थ्रॉटल / डिब्यू का उपयोग करना । मेरी राय में आपके रूप में हर एक क्षेत्र की घटनाओं में देरी करने की कोई आवश्यकता नहीं है।

बस अपने $ स्कोप को लपेटें। $।

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

आपको इसे $ स्कोप में लपेटना होगा। $ अप्लाई
आकिल फर्नांडीस

3

एक अन्य समाधान मॉडल अपडेट में देरी की कार्यक्षमता जोड़ना है। सरल निर्देश एक चाल करने के लिए लगता है:

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

उपयोग:

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

तो आप बस के delayed-modelस्थान पर उपयोग करें ng-modelऔर वांछित को परिभाषित करें data-delay

डेमो: http://plnkr.co/edit/OmB4C3jtUD2Wjq5kzTSU?ppreview


हे! क्या आप बता सकते हैं कि कैसे model: '=delayedModel'काम कर रहा है? या आप मुझे एक लिंक पर इंगित कर सकते हैं जहां मैं इसे पा सकता हूं?
आकाश अग्रवाल

@ अकाशअग्रवाल यह दो तरह से डेटा बाइंडिंग है। इसके बारे में पढ़ें यहाँ docs.angularjs.org/api/ng.$compile
dfsq

1
@dfsq मैं एनजी-परिवर्तन का उपयोग कर रहा था और जब भी पाठ में कोई परिवर्तन होता है तो यह ट्रिगर हो जाता है। जब एक निर्देश परिभाषित किया जाता है तो मैं इसका उपयोग नहीं कर सकता। element.on('change')केवल धुंधला पर चलाता है। (१) क्या आसपास कोई काम है? (२) पाठ परिवर्तन पर नियंत्रक के कार्य को कैसे कहें?
व्यास राव

0

मैंने एक निर्देश के साथ इस समस्या को हल किया कि मूल रूप से यह क्या करता है कि वास्तविक एनजी-मॉडल को एक विशेष विशेषता पर बांधा जाए, जिसे मैं निर्देश में देखता हूं, फिर एक डेबिट सेवा का उपयोग करके मैं अपने निर्देश को अद्यतन करता हूं, इसलिए उपयोगकर्ता चर पर देखता है वह एनजी-मॉडल के बजाय डेब्यू-मॉडल से बंधता है।

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

उपयोग:

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

और नियंत्रक में:

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

Jsfiddle में डेमो: http://jsfiddle.net/6K7Kd/37/

$ डेबिट सेवा यहां पाई जा सकती है: http://jsfiddle.net/Warspawn/6K7Kd/

अंततः निर्देशन के लिए प्रेरित करें http://jsfiddle.net/fctZH/12/


0

कोणीय 1.3 में एनजी-मॉडल-ऑप्शन की चर्चा होगी, लेकिन तब तक, आपको एक टाइमर का उपयोग करना होगा जैसे कि जोसु इबारा ने कहा। हालांकि, अपने कोड में उन्होंने हर कुंजी प्रेस पर एक टाइमर लॉन्च किया। इसके अलावा, वह सेटटाइमआउट का उपयोग कर रहा है, जब एंगुलर में $ टाइमआउट का उपयोग करना है या सेट टाइमआउट के अंत में $ लागू का उपयोग करना है।


0

हर कोई घड़ी का उपयोग क्यों करना चाहता है? तुम भी एक समारोह का उपयोग कर सकते हैं:

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

0

मुझे लगता है कि यहां पर सबसे आसान तरीका है कि आप जोंस को प्रीलोड करें या $dirtyफिर एक बार लोड करें और फिर फिल्टर सर्च बाकी का ध्यान रखेगा। यह आपको अतिरिक्त http कॉल और प्रीलोडेड डेटा के साथ बहुत तेज़ी से बचाएगा। स्मृति को चोट पहुंचेगी, लेकिन इसके लायक है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.