भारी डेटासेट (angular.js) पर ngRepeat के प्रदर्शन में सुधार कैसे करें?


165

मेरे पास लगभग 10 क्षेत्रों के साथ कई हजार पंक्तियों का एक बड़ा डेटासेट है, लगभग 2 एमबी डेटा। मुझे इसे ब्राउज़र में प्रदर्शित करने की आवश्यकता है। अधिकांश सरल दृष्टिकोण (डेटा प्राप्त करें, इसे डालें $scope, ng-repeat=""अपना काम करने दें ) ठीक काम करता है, लेकिन यह ब्राउज़र को लगभग आधे मिनट तक फ्रीज करता है जब वह डोम में नोड्स डालना शुरू करता है। मुझे इस समस्या से कैसे संपर्क करना चाहिए?

एक विकल्प पंक्तियों को $scopeवृद्धिशील रूप से जोड़ना और ngRepeatअगले एक पर जाने से पहले डोम में एक चंक डालने का इंतजार करना है । लेकिन AFAIK ngRepeat वापस रिपोर्ट नहीं करता है जब यह "दोहराता" है, तो यह बदसूरत होने वाला है।

अन्य विकल्प सर्वर पर डेटा को पृष्ठों में विभाजित करना और उन्हें कई अनुरोधों में लाना है, लेकिन यह भी बदसूरत है।

मैंने कुछ की तलाश में कोणीय प्रलेखन के माध्यम से देखा ng-repeat="data in dataset" ng-repeat-steps="500", लेकिन कुछ भी नहीं मिला। मैं कोणीय तरीके से काफी नया हूं, इसलिए यह संभव है कि मैं बिंदु को पूरी तरह से याद कर रहा हूं। इस पर सर्वोत्तम अभ्यास क्या हैं?


10
क्या आप वास्तव में सभी पंक्तियों को प्रदर्शित करना चाहते हैं? केवल वही प्रदर्शित करने के बारे में जो उपयोगकर्ता को दिखाई देने वाली कई पंक्तियों में हो सकता है। उदाहरण के लिए, आप limitToकेवल 20 आइटम प्रदर्शित करने के लिए उपयोग कर सकते हैं : <p ng-repeat="data in dataset | limitTo:20">{{data}}</p>यह केवल 20 आइटम दिखाता है। तब आप पृष्ठों का उपयोग कर सकते हैं और अगले 10 आइटम या ऐसा कुछ दिखा सकते हैं। :)
आंद्रेएम 96

उस "रिपोर्ट के वापस आने के बाद जब वह 'पुनरावृत्ति' समाप्त करता है" तो आप एनजी-रिपीट के अलावा एक कस्टम निर्देश का उपयोग कर सकते हैं। (यहां देखें चयनित जवाब) stackoverflow.com/questions/13471129/…
mayankcpdixit

इस सवाल का संदर्भ दें यह निश्चित रूप से आपकी मदद करेगा। [यहाँ लिंक विवरण दर्ज करें] [1] [१]: stackoverflow.com/questions/25481021/…
महेश

जवाबों:


159

मैं @ आंद्रेएम 96 से सहमत हूं कि सबसे अच्छा तरीका केवल सीमित मात्रा में पंक्तियों को प्रदर्शित करना है, तेज और बेहतर UX, यह एक पृष्ठांकन या अनंत स्क्रॉल के साथ किया जा सकता है।

कोणीय साथ अनंत स्क्रॉल के साथ बहुत आसान है limitTo फिल्टर। आपको बस प्रारंभिक सीमा निर्धारित करनी है और जब उपयोगकर्ता अधिक डेटा मांगता है (मैं सादगी के लिए एक बटन का उपयोग कर रहा हूं) तो आप सीमा बढ़ाते हैं।

<table>
    <tr ng-repeat="d in data | limitTo:totalDisplayed"><td>{{d}}</td></tr>
</table>
<button class="btn" ng-click="loadMore()">Load more</button>

//the controller
$scope.totalDisplayed = 20;

$scope.loadMore = function () {
  $scope.totalDisplayed += 20;  
};

$scope.data = data;

यहाँ एक JsBin है

यह दृष्टिकोण फोन के लिए एक समस्या हो सकती है क्योंकि आमतौर पर वे बहुत सारे डेटा स्क्रॉल करते समय पिछड़ जाते हैं, इसलिए इस मामले में मुझे लगता है कि एक पेजिनेशन बेहतर है।

ऐसा करने के लिए आपको सीमाबद्ध फ़िल्टर की आवश्यकता होगी और प्रदर्शित किए जा रहे डेटा के शुरुआती बिंदु को परिभाषित करने के लिए एक कस्टम फ़िल्टर की भी आवश्यकता होगी।

यहां एक जेएसबीएन एक अंकन के साथ है।


अच्छा विकल्प !!! यदि आप सभी वस्तुओं को दिखाने के लिए बाध्य हैं, तो आप किसी भी विधि का उपयोग कर सकते हैं। DOM या किसी चीज़ में एक प्रविष्टि के बाद कोई लोडिंग साइन या एक?
मयंकपदीक्षित

क्या आपका मतलब डेटा लोड होने के दौरान "लोडिंग ..." या कुछ और दिखाना है?
बर्ट्रेंड

1
@Sumit limitTo को एनजी-रिपीट स्कोप पर लागू किया जाएगा, इसलिए परिणाम एक नया एरे होगा, जिसे एनजी-रिपीट करने के लिए पास किया जाएगा, आपका डेटा ऐरे अभी भी वही है और आप अभी भी सभी कंटेंट को खोज सकते हैं।
बर्ट्रेंड

12
यदि उपयोगकर्ता लोडमोर को 10 बार दबाता है और प्रत्येक प्रेस 100 और आइटम जोड़ता है, तो यह प्रदर्शन में सुधार कैसे कर सकता है?
हरिसज़मन

5
@hariszaman मैं सहमत हूँ। यह प्रदर्शन में सुधार नहीं करता है। यह सिर्फ खराब प्रदर्शन में देरी करता है। जब तक आप इसे वर्चुअलाइज नहीं कर रहे हैं (जो ui- ग्रिड करता है) अनंत स्क्रॉल आपको परेशानी में डाल देगा।
रिचार्ड

41

सबसे बड़े डेटासेट्स के साथ इन चुनौतियों पर काबू पाने के लिए सबसे गर्म - और यकीनन सबसे स्केलेबल - दृष्टिकोण, इओनिक के संग्रह के दृष्टिकोण और उसके जैसे अन्य कार्यान्वयन के दृष्टिकोण से सन्निहित है । इसके लिए एक फैंसी शब्द है, 'रोना रोना' , लेकिन आप इसे इस रूप में जोड़ सकते हैं: केवल मनमाने ढंग से (लेकिन अभी भी उच्च) पृष्ठांकित संख्या जैसे 50, 100, 500 ... के बदले प्रदान किए गए DOM तत्वों की गिनती को सीमित न करें , उपयोगकर्ता के रूप में केवल कई तत्वों को सीमित कर सकते हैं

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

जबकि, collectionRepeatदृष्टिकोण केवल इतने सारे तत्वों का उपयोग करना है जो व्यूपोर्ट में फिट होंगे, और फिर उन्हें रीसायकल करेंगे । जैसा कि एक तत्व दृश्य से बाहर घूमता है, यह रेंडर ट्री से अलग हो जाता है, सूची में एक नए आइटम के लिए डेटा के साथ फिर से भर दिया जाता है, फिर सूची के दूसरे छोर पर रेंडर ट्री को reattached किया जाता है। यह सबसे तेज़ तरीका है जो मनुष्य को DOM के अंदर और बाहर नई जानकारी प्राप्त करने के लिए, मौजूदा तत्वों के एक सीमित सेट का उपयोग करने के बजाय, बनाने / नष्ट करने ... बनाने / नष्ट करने के पारंपरिक चक्र के बारे में बताता है। इस दृष्टिकोण का उपयोग करके, आप वास्तव में एक अनंत स्क्रॉल लागू कर सकते हैं ।

ध्यान दें कि आपको Ionic का उपयोग / हैक / अनुकूलन collectionRepeat, या इसके जैसे किसी अन्य उपकरण का उपयोग करने की आवश्यकता नहीं है । इसलिए वे इसे ओपन-सोर्स कहते हैं। :-) (यह कहा, Ionic टीम कुछ बहुत सरल चीजें कर रही है, आपके ध्यान के योग्य है।)


रिएक्ट में कुछ ऐसा ही करने का कम से कम एक उत्कृष्ट उदाहरण है। केवल अपडेट की गई सामग्री के साथ तत्वों को पुन: चक्रित करने के बजाय, आप बस उस पेड़ में कुछ भी रेंडर नहीं करने का विकल्प चुन रहे हैं जो देखने में नहीं है। यह 5000 वस्तुओं पर तेजी से धधक रहा है, हालांकि उनका बहुत ही सरल POC कार्यान्वयन झिलमिलाहट की थोड़ी अनुमति देता है ...


इसके अलावा ... कुछ अन्य पोस्ट को इको करने के लिए track by, छोटे डेटासेट के साथ, गंभीर रूप से मददगार है। इसे अनिवार्य मानें।


Ionic टीम द्वारा भयानक विचार। मुझे आश्चर्य है कि यदि मूल विचार कैसे प्रस्तुत किए गए हैं?
ब्रैडली फ्लड

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

36

मैं यह देखने की सलाह देता हूं:

ऑप्टिमाइज़िंग एंगुलरजेएस: 1200ms से 35ms

उन्होंने 4 भागों में एनजी-रिपीट का अनुकूलन करके एक नया निर्देश दिया:

अनुकूलन # 1: कैश डोम तत्व

अनुकूलन # 2: देखने वालों को अलग करना

अनुकूलन # 3: तत्व का निर्माण

अनुकूलन # 4: छिपे हुए तत्वों के लिए बायपास पर नजर रखने वाले

परियोजना गितुब पर यहां है:

उपयोग:

1- इन फाइलों को अपने सिंगल-पेज ऐप में शामिल करें:

  • core.js
  • scalyr.js
  • slyEvaluate.js
  • slyRepeat.js

2- मॉड्यूल निर्भरता जोड़ें:

var app = angular.module("app", ['sly']);

3- एनजी-रिपीट की जगह लें

<tr sly-repeat="m in rows"> .....<tr>

का आनंद लें!


4
मुझे लगता है कि इस scalyr.js में पहले से ही अन्य फाइलें शामिल हैं। क्योंकि बिल्ड स्क्रिप्ट का परिणाम है।
dnocode

मैं Scalyr का उपयोग करने की कोशिश की, लेकिन फिल्टर काम नहीं करता है। <tr sly-repeat = "main.customers में विकल्प। फ़िल्टर: search_input | limitTo: 20">
aldesabido

यह बेहद मददगार है। मैं इसे एक AngularJS 1.6 ऐप पर उपयोग कर रहा हूं, जहां क्लाइंट बहुत सारे डेटा देखना चाहता है (आम तौर पर मैं डेटा तत्वों को पेजिंग / कम करने के साथ डिज़ाइन करता हूं लेकिन क्लाइंट को एक साथ बहुत सारे डेटा की तुलना करने की आवश्यकता होती है)। अब तक इस लाइब्रेरी की वजह से कोशिकाओं का ग्रिड बेकार हो गया है। लेकिन यह परिवाद 1.2 दिन पहले एंगुलरजेएस में लिखा गया था, इसलिए मैं समस्याओं की सावधानीपूर्वक जांच करूंगा।
फ्लायर

इस समय मैं जो बता सकता हूं उससे gatedScope.js फ़ाइल (323 लाइनें) केवल एक ही है जिसे AngularJS के अधिक वर्तमान संस्करणों पर चलने योग्य सत्यापित करने की आवश्यकता है। यह पुल अनुरोध उल्लेखनीय है: github.com/karser/angular/commit/… । यह सिग्नेचर रूट को अपडेट करता है। $ नया।
उड़ता

सभी चार js फ़ाइलों को शामिल किया और इस्तेमाल किया, sly-repeatलेकिन कुछ भी नहीं मदद की मुझे परिणाम अभी भी धीमा है और ब्राउज़र लैग्स का भी उल्लंघन हो रहा है [Violation] 'setTimeout' handler took 54ms,[Violation] 'scroll' handler took 1298ms
गौरव अग्रवाल

15

उपरोक्त सभी संकेतों जैसे ट्रैक बाय और छोटे छोरों के अलावा, इसने भी मुझे बहुत मदद की

<span ng-bind="::stock.name"></span>

यह कोड एक बार लोड होने के बाद नाम को प्रिंट करेगा, और उसके बाद इसे देखना बंद कर देगा। इसी तरह, एनजी-रिपीट के लिए, इसका उपयोग किया जा सकता है

<div ng-repeat="stock in ::ctrl.stocks">{{::stock.name}}</div>

हालाँकि यह केवल 1.3 और उच्चतर संस्करण के लिए काम करता है। से http://www.befundoo.com/blog/optimizing-ng-repeat-in-angularjs/


क्या आपको ::दोहराने के साथ-साथ अभिव्यक्ति पर भी ज़रूरत है ? डॉक्स अन्यथा कहते हैं, लेकिन मुझे यह परीक्षण करने के तरीके का यकीन नहीं है कि यह काम कर रहा है। docs.angularjs.org/guide/expression
रामिरेज़

12

प्रदर्शन को बढ़ाने के लिए आप "ट्रैक बाय" का उपयोग कर सकते हैं:

<div ng-repeat="a in arr track by a.trackingKey">

की तुलना में तेज:

<div ng-repeat="a in arr">

रेफरी: https://www.airpair.com/angularjs/posts/angularjs-performance-large-applications


1
यह वास्तव में प्रदर्शन के लिए मदद नहीं करता है। देखें jsperf.com/ng-repeat-vs-ng-repeat-with-trace-by-id
İlter

हर बार जब आप नया डेटा प्राप्त करते हैं, तब से आप ट्रैक तत्व को शुरुआत से ट्रैक नहीं करते हैं। परिणामस्वरूप यह प्रदर्शन में सुधार करता है।
user1920302

2
यह तभी उपयोगी होता है जब एनजी-रिपीट में डेटा बदलता है। प्रारंभिक भार के लिए, यह प्रदर्शन में सुधार नहीं कर सकता है।
सुमेश कुट्टन

11

यदि आपकी सभी पंक्तियों की ऊंचाई समान है, तो आपको निश्चित रूप से वर्चुअलाइज़िंग एनजी-रिपीट पर एक नज़र डालनी चाहिए: http://kamilkp.github.io/angular-vs-repeat/

यह डेमो बहुत आशाजनक लगता है (और यह जड़त्वीय स्क्रॉल का समर्थन करता है)


2
मोबाइल पर स्क्रॉल प्रदर्शन स्वीकार्य नहीं है (स्क्रॉल इवेंट मोबाइल iOS पर फायर नहीं करता है (केवल 8 से ऊपर)
जॉनी

9

नियम नंबर 1: उपयोगकर्ता को कभी भी किसी चीज का इंतजार न करने दें।

यह ध्यान में रखते हुए कि 10 सेकंड की जरूरत वाले जीवन के बढ़ते पृष्ठ को रिक्त स्क्रीन से पहले 3 सेकंड प्रतीक्षा करने की तुलना में तेजी से प्रकट होता है और सभी को एक बार मिलता है।

तो बजाय मेकअप पेज तेजी से, बस पृष्ठ जाने दिखाई तेजी से हो सकता है, भले ही अंतिम परिणाम धीमी है:

function applyItemlist(items){
    var item = items.shift();
    if(item){
        $timeout(function(){
            $scope.items.push(item);
            applyItemlist(items);
        }, 0); // <-- try a little gap of 10ms
    }
}

ऊपर दिए गए कोड सूची को पंक्ति-दर-पंक्ति बढ़ते हुए दिखाई देते हैं, और हमेशा एक साथ प्रस्तुत करने की तुलना में धीमी होती है। लेकिन उपयोगकर्ता के लिए यह तेज़ प्रतीत होता है।


html पेज में इस फंक्शन का उपयोग कैसे करें?
एंटोनीस

9

वर्चुअल स्क्रॉलिंगबड़ी सूचियों और बड़े डेटासेट से निपटने पर स्क्रॉलिंग स्क्रॉलिंग को बेहतर बनाने का एक और तरीका है ।

इसे लागू करने का एक तरीका कोणीय सामग्री का उपयोग md-virtual-repeatकरना है क्योंकि यह 50,000 वस्तुओं के साथ इस डेमो पर प्रदर्शित होता है

वर्चुअल रिपीट के प्रलेखन से सीधे लिया गया:

वर्चुअल रिपीट एनजी-रिपीट के लिए एक सीमित विकल्प है जो कंटेनर को भरने और उन्हें उपयोगकर्ता के स्क्रॉल के रूप में रीसाइक्लिंग करने के लिए केवल पर्याप्त डोम नोड्स प्रदान करता है।


2
वाह, मुझे लगता है कि यह सबसे दिलचस्प जवाब है। क्या यह कोणीय के पुराने संस्करण के साथ काम करेगा? (उदा। १.२)
थारीक नुगरोहोटो

2
@ThariqNugrohotomo कृपया ध्यान दें कि कोणीय सामग्री का उपयोग करने के लिए कोणीय 1.3.x या उच्चतर के उपयोग की आवश्यकता होती है। समर्थन के लिए भी धन्यवाद, मैं वास्तव में आभासी दोहराव से चकित हूं और हम पहले से ही मोबाइल ऐप पर इसका उपयोग कर रहे हैं जो परिणामों की एक लंबी सूची प्रदर्शित करता है।
सारेंटिस टोफस

6

एक अन्य संस्करण @Steffomio

प्रत्येक आइटम को व्यक्तिगत रूप से जोड़ने के बजाय हम आइटम को विखंडू से जोड़ सकते हैं।

// chunks function from here: 
// http://stackoverflow.com/questions/8495687/split-array-into-chunks#11764168
var chunks = chunk(folders, 100);

//immediate display of our first set of items
$scope.items = chunks[0];

var delay = 100;
angular.forEach(chunks, function(value, index) {
    delay += 100;

    // skip the first chuck
    if( index > 0 ) {
        $timeout(function() {
            Array.prototype.push.apply($scope.items,value);
        }, delay);
    }       
});

दिलचस्प विचार। मैंने इसे ~ 8000 तत्वों की एक सरणी पर आज़माया, और जब इसने पृष्ठ को शुरू में अधिक प्रतिक्रियाशील बना दिया, तो यह प्रत्येक चंक के बाद कम प्रतिक्रियाशील हो गया।
पॉल ब्रैनन

500 से अधिक आइटम होने के बाद मेरे ऐप पर यह एक बड़ी समस्या थी। मैं इसके बजाय पृष्ठ पर अंक लगाना या अनंत लोड करने का सुझाव देता हूं।
जॉल्सेगो

0

कभी-कभी क्या हुआ, आपको कुछ एमएस में सर्वर (या बैक-एंड) से डेटा मिलता है (उदाहरण के लिए मैं इसे 100 मी मान रहा हूं) लेकिन हमारे वेब पेज में प्रदर्शित होने में अधिक समय लगता है (मान लीजिए कि यह 900ms में ले रहा है) प्रदर्शन)।

तो, यहाँ क्या हो रहा है 800ms यह सिर्फ वेब पेज रेंडर करने के लिए ले जा रहा है।

मैंने अपने वेब एप्लिकेशन में जो किया है, वह डेटा की सूची प्रदर्शित करने के लिए मैंने पृष्ठांकन (या आप अनंत स्क्रॉलिंग का भी उपयोग कर सकते हैं ) का उपयोग किया है। मान लीजिए कि मैं 50 डेटा / पृष्ठ दिखा रहा हूं।

इसलिए मैं एक बार में सभी डेटा को लोड नहीं करूंगा, केवल 50 डेटा मैं शुरू में लोड कर रहा हूं जो केवल 50ms लेता है (मैं यहां मान रहा हूं)।

इसलिए यहाँ कुल समय 900ms से घटकर 150ms हो गया, एक बार उपयोगकर्ता अगले पृष्ठ का अनुरोध करता है और फिर अगले 50 डेटा प्रदर्शित करता है।

आशा है कि इससे आपको प्रदर्शन को बेहतर बनाने में मदद मिलेगी। शुभकामनाएं


0
Created a directive (ng-repeat with lazy loading) 

जो डेटा को लोड करता है जब वह पृष्ठ के निचले हिस्से तक पहुंचता है और पहले से लोड किए गए डेटा के आधे को हटा देता है और जब यह फिर से पिछले डेटा के शीर्ष पर पहुंच जाता है (पृष्ठ संख्या के आधार पर) वर्तमान डेटा के आधे को हटाकर लोड किया जाएगा ताकि डोम पर एक समय में केवल सीमित डेटा मौजूद होता है जो लोड पर संपूर्ण डेटा रेंडर करने के बजाय बेहतर प्रदर्शन की ओर ले जाता है।

HTML कोड:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="ListController">
  <div class="row customScroll" id="customTable" datafilter pagenumber="pageNumber" data="rowData" searchdata="searchdata" itemsPerPage="{{itemsPerPage}}"  totaldata="totalData"   selectedrow="onRowSelected(row,row.index)"  style="height:300px;overflow-y: auto;padding-top: 5px">

    <!--<div class="col-md-12 col-xs-12 col-sm-12 assign-list" ng-repeat="row in CRGC.rowData track by $index | orderBy:sortField:sortReverse | filter:searchFish">-->
    <div class="col-md-12 col-xs-12 col-sm-12 pdl0 assign-list" style="padding:10px" ng-repeat="row in rowData" ng-hide="row[CRGC.columns[0].id]=='' && row[CRGC.columns[1].id]==''">
        <!--col1-->

        <div ng-click ="onRowSelected(row,row.index)"> <span>{{row["sno"]}}</span> <span>{{row["id"]}}</span> <span>{{row["name"]}}</span></div>
      <!--   <div class="border_opacity"></div> -->
    </div>

</div>

  </body>

</html>

कोणीय कोड:

var app = angular.module('plunker', []);
var x;
ListController.$inject = ['$scope', '$timeout', '$q', '$templateCache'];

function ListController($scope, $timeout, $q, $templateCache) {
  $scope.itemsPerPage = 40;
  $scope.lastPage = 0;
  $scope.maxPage = 100;
  $scope.data = [];
  $scope.pageNumber = 0;


  $scope.makeid = function() {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < 5; i++)
      text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
  }


  $scope.DataFormFunction = function() {
      var arrayObj = [];
      for (var i = 0; i < $scope.itemsPerPage*$scope.maxPage; i++) {
          arrayObj.push({
              sno: i + 1,
              id: Math.random() * 100,
              name: $scope.makeid()
          });
      }
      $scope.totalData = arrayObj;
      $scope.totalData = $scope.totalData.filter(function(a,i){ a.index = i; return true; })
      $scope.rowData = $scope.totalData.slice(0, $scope.itemsperpage);
    }
  $scope.DataFormFunction();

  $scope.onRowSelected = function(row,index){
    console.log(row,index);
  }

}

angular.module('plunker').controller('ListController', ListController).directive('datafilter', function($compile) {
  return {
    restrict: 'EAC',
    scope: {
      data: '=',
      totalData: '=totaldata',
      pageNumber: '=pagenumber',
      searchdata: '=',
      defaultinput: '=',
      selectedrow: '&',
      filterflag: '=',
      totalFilterData: '='
    },
    link: function(scope, elem, attr) {
      //scope.pageNumber = 0;
      var tempData = angular.copy(scope.totalData);
      scope.totalPageLength = Math.ceil(scope.totalData.length / +attr.itemsperpage);
      console.log(scope.totalData);
      scope.data = scope.totalData.slice(0, attr.itemsperpage);
      elem.on('scroll', function(event) {
        event.preventDefault();
      //  var scrollHeight = angular.element('#customTable').scrollTop();
      var scrollHeight = document.getElementById("customTable").scrollTop
        /*if(scope.filterflag && scope.pageNumber != 0){
        scope.data = scope.totalFilterData;
        scope.pageNumber = 0;
        angular.element('#customTable').scrollTop(0);
        }*/
        if (scrollHeight < 100) {
          if (!scope.filterflag) {
            scope.scrollUp();
          }
        }
        if (angular.element(this).scrollTop() + angular.element(this).innerHeight() >= angular.element(this)[0].scrollHeight) {
          console.log("scroll bottom reached");
          if (!scope.filterflag) {
            scope.scrollDown();
          }
        }
        scope.$apply(scope.data);

      });

      /*
       * Scroll down data append function
       */
      scope.scrollDown = function() {
          if (scope.defaultinput == undefined || scope.defaultinput == "") { //filter data append condition on scroll
            scope.totalDataCompare = scope.totalData;
          } else {
            scope.totalDataCompare = scope.totalFilterData;
          }
          scope.totalPageLength = Math.ceil(scope.totalDataCompare.length / +attr.itemsperpage);
          if (scope.pageNumber < scope.totalPageLength - 1) {
            scope.pageNumber++;
            scope.lastaddedData = scope.totalDataCompare.slice(scope.pageNumber * attr.itemsperpage, (+attr.itemsperpage) + (+scope.pageNumber * attr.itemsperpage));
            scope.data = scope.totalDataCompare.slice(scope.pageNumber * attr.itemsperpage - 0.5 * (+attr.itemsperpage), scope.pageNumber * attr.itemsperpage);
            scope.data = scope.data.concat(scope.lastaddedData);
            scope.$apply(scope.data);
            if (scope.pageNumber < scope.totalPageLength) {
              var divHeight = $('.assign-list').outerHeight();
              if (!scope.moveToPositionFlag) {
                angular.element('#customTable').scrollTop(divHeight * 0.5 * (+attr.itemsperpage));
              } else {
                scope.moveToPositionFlag = false;
              }
            }


          }
        }
        /*
         * Scroll up data append function
         */
      scope.scrollUp = function() {
          if (scope.defaultinput == undefined || scope.defaultinput == "") { //filter data append condition on scroll
            scope.totalDataCompare = scope.totalData;
          } else {
            scope.totalDataCompare = scope.totalFilterData;
          }
          scope.totalPageLength = Math.ceil(scope.totalDataCompare.length / +attr.itemsperpage);
          if (scope.pageNumber > 0) {
            this.positionData = scope.data[0];
            scope.data = scope.totalDataCompare.slice(scope.pageNumber * attr.itemsperpage - 0.5 * (+attr.itemsperpage), scope.pageNumber * attr.itemsperpage);
            var position = +attr.itemsperpage * scope.pageNumber - 1.5 * (+attr.itemsperpage);
            if (position < 0) {
              position = 0;
            }
            scope.TopAddData = scope.totalDataCompare.slice(position, (+attr.itemsperpage) + position);
            scope.pageNumber--;
            var divHeight = $('.assign-list').outerHeight();
            if (position != 0) {
              scope.data = scope.TopAddData.concat(scope.data);
              scope.$apply(scope.data);
              angular.element('#customTable').scrollTop(divHeight * 1 * (+attr.itemsperpage));
            } else {
              scope.data = scope.TopAddData;
              scope.$apply(scope.data);
              angular.element('#customTable').scrollTop(divHeight * 0.5 * (+attr.itemsperpage));
            }
          }
        }
    }
  };
});

निर्देशन के साथ डेमो

Another Solution: If you using UI-grid in the project then  same implementation is there in UI grid with infinite-scroll.

विभाजन की ऊंचाई के आधार पर यह डेटा को लोड करता है और स्क्रॉल पर नया डेटा एपेंड होगा और पिछला डेटा हटा दिया जाएगा।

HTML कोड:

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.css" type="text/css" />
    <script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.20/angular.js" data-semver="1.3.20"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.6/ui-grid.js"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="ListController">
     <div class="input-group" style="margin-bottom: 15px">
      <div class="input-group-btn">
        <button class='btn btn-primary' ng-click="resetList()">RESET</button>
      </div>
      <input class="form-control" ng-model="search" ng-change="abc()">
    </div>

    <div data-ui-grid="gridOptions" class="grid" ui-grid-selection  data-ui-grid-infinite-scroll style="height :400px"></div>

    <button ng-click="getProductList()">Submit</button>
  </body>

</html>

कोणीय कोड:

var app = angular.module('plunker', ['ui.grid', 'ui.grid.infiniteScroll', 'ui.grid.selection']);
var x;
angular.module('plunker').controller('ListController', ListController);
ListController.$inject = ['$scope', '$timeout', '$q', '$templateCache'];

function ListController($scope, $timeout, $q, $templateCache) {
    $scope.itemsPerPage = 200;
    $scope.lastPage = 0;
    $scope.maxPage = 5;
    $scope.data = [];

    var request = {
        "startAt": "1",
        "noOfRecords": $scope.itemsPerPage
    };
    $templateCache.put('ui-grid/selectionRowHeaderButtons',
        "<div class=\"ui-grid-selection-row-header-buttons \" ng-class=\"{'ui-grid-row-selected': row.isSelected}\" ><input style=\"margin: 0; vertical-align: middle\" type=\"checkbox\" ng-model=\"row.isSelected\" ng-click=\"row.isSelected=!row.isSelected;selectButtonClick(row, $event)\">&nbsp;</div>"
    );


    $templateCache.put('ui-grid/selectionSelectAllButtons',
        "<div class=\"ui-grid-selection-row-header-buttons \" ng-class=\"{'ui-grid-all-selected': grid.selection.selectAll}\" ng-if=\"grid.options.enableSelectAll\"><input style=\"margin: 0; vertical-align: middle\" type=\"checkbox\" ng-model=\"grid.selection.selectAll\" ng-click=\"grid.selection.selectAll=!grid.selection.selectAll;headerButtonClick($event)\"></div>"
    );

    $scope.gridOptions = {
        infiniteScrollDown: true,
        enableSorting: false,
        enableRowSelection: true,
        enableSelectAll: true,
        //enableFullRowSelection: true,
        columnDefs: [{
            field: 'sno',
            name: 'sno'
        }, {
            field: 'id',
            name: 'ID'
        }, {
            field: 'name',
            name: 'My Name'
        }],
        data: 'data',
        onRegisterApi: function(gridApi) {
            gridApi.infiniteScroll.on.needLoadMoreData($scope, $scope.loadMoreData);
            $scope.gridApi = gridApi;
        }
    };
    $scope.gridOptions.multiSelect = true;
    $scope.makeid = function() {
        var text = "";
        var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

        for (var i = 0; i < 5; i++)
            text += possible.charAt(Math.floor(Math.random() * possible.length));

        return text;
    }
    $scope.abc = function() {
        var a = $scope.search;
        x = $scope.searchData;
        $scope.data = x.filter(function(arr, y) {
            return arr.name.indexOf(a) > -1
        })
        console.log($scope.data);
        if ($scope.gridApi.grid.selection.selectAll)
            $timeout(function() {
                $scope.gridApi.selection.selectAllRows();
            }, 100);
    }


    $scope.loadMoreData = function() {
        var promise = $q.defer();
        if ($scope.lastPage < $scope.maxPage) {
            $timeout(function() {
                var arrayObj = [];
                for (var i = 0; i < $scope.itemsPerPage; i++) {
                    arrayObj.push({
                        sno: i + 1,
                        id: Math.random() * 100,
                        name: $scope.makeid()
                    });
                }

                if (!$scope.search) {
                    $scope.lastPage++;
                    $scope.data = $scope.data.concat(arrayObj);
                    $scope.gridApi.infiniteScroll.dataLoaded();
                    console.log($scope.data);
                    $scope.searchData = $scope.data;
                    // $scope.data = $scope.searchData;
                    promise.resolve();
                    if ($scope.gridApi.grid.selection.selectAll)
                        $timeout(function() {
                            $scope.gridApi.selection.selectAllRows();
                        }, 100);
                }


            }, Math.random() * 1000);
        } else {
            $scope.gridApi.infiniteScroll.dataLoaded();
            promise.resolve();
        }
        return promise.promise;
    };

    $scope.loadMoreData();

    $scope.getProductList = function() {

        if ($scope.gridApi.selection.getSelectedRows().length > 0) {
            $scope.gridOptions.data = $scope.resultSimulatedData;
            $scope.mySelectedRows = $scope.gridApi.selection.getSelectedRows(); //<--Property undefined error here
            console.log($scope.mySelectedRows);
            //alert('Selected Row: ' + $scope.mySelectedRows[0].id + ', ' + $scope.mySelectedRows[0].name + '.');
        } else {
            alert('Select a row first');
        }
    }
    $scope.getSelectedRows = function() {
        $scope.mySelectedRows = $scope.gridApi.selection.getSelectedRows();
    }
    $scope.headerButtonClick = function() {

        $scope.selectAll = $scope.grid.selection.selectAll;

    }
}

अनन्त-स्क्रॉल डेमो के साथ UI ग्रिड के साथ डेमो


किसी समाधान का लिंक स्वागत योग्य है, लेकिन कृपया सुनिश्चित करें कि आपका उत्तर इसके बिना उपयोगी है: लिंक के चारों ओर संदर्भ जोड़ें ताकि आपके साथी उपयोगकर्ताओं को कुछ अंदाजा हो कि यह क्या है और यह क्यों है, तो पृष्ठ के सबसे प्रासंगिक हिस्से को उद्धृत करें ' मामले में लक्ष्य पृष्ठ अनुपलब्ध होने पर पुनः लिंक करना। उत्तर जो किसी लिंक से थोड़ा अधिक हैं, उन्हें हटाया जा सकता है
S

-2

बड़े डेटा सेट और कई वैल्यू ड्रॉप डाउन के ng-optionsबजाय इसका उपयोग करना बेहतर है ng-repeat

ng-repeatयह धीमा है क्योंकि यह सभी आने वाले मानों पर लूप करता है लेकिन ng-optionsबस चुनिंदा विकल्प को प्रदर्शित करता है।

ng-options='state.StateCode as state.StateName for state in States'>

की तुलना में बहुत तेजी से

<option ng-repeat="state in States" value="{{state.StateCode}}">
    {{state.StateName }}
</option>

क्या आपने एनजी-विकल्पों के प्रदर्शन की जांच की? मैं अपने कोड को इष्टतम बनाने की कोशिश कर रहा हूं और इससे मदद नहीं मिली। स्पीड एनजी-रिपीट के समान है। -1
12

केवल चुनिंदा के लिए काम करता है, एनजी-रिपीट रास्ता अधिक शक्तिशाली है। फिर भी यह सच है कि एनजी-विकल्प एनजी-रिपीट की तुलना में तेज़ है। AngularJs डॉक्स में मतभेदों के लिए 2000 वस्तुओं का उल्लेख है: docs.angularjs.org/api/ng/directive/select
kaiser
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.