2013-07-16 8 views
17

के साथ पेजिनेशन को कैसे संभाला जाए मेरे पास एक div है जो observeableArray से जुड़ने के लिए सेट है, लेकिन मैं केवल observeableArray से किसी भी समय 50 से अधिक आइटम दिखाना चाहता हूं। मैं पृष्ठ पर इंडेक्स के साथ पिछले और अगले बटन के साथ पेजिनेशन के साथ इसे संभालना चाहता हूं ताकि उपयोगकर्ता संग्रह से वस्तुओं के पृष्ठों के माध्यम से चले जा सकें।
मुझे पता है कि मैं शायद computedObservable और कस्टम डेटा बाध्यकारी के साथ ऐसा कर सकता हूं लेकिन मुझे यकीन नहीं है कि यह कैसे करें (मैं अभी भी एक नॉकआउट नियोफेट हूं)।
क्या कोई मुझे सही दिशा में इंगित कर सकता है?नॉकआउट

यहाँ मेरी कोड है (जे एस टाइपप्रति में है):

<div class="container-fluid"> 
    <div class="row-fluid"> 
     <div class="span12"> 
      <%= 
      if params[:q] 
       render 'active_search.html.erb' 
      else 
       render 'passive_search.html.erb' 
      end 
      %> 
      <%= form_tag("/search", method: "get", :class => "form-search form-inline") do %> 
      <%= label_tag(:q, "Search for:") %> 
      <%= text_field_tag(:q, nil, class:"input-medium search-query") %> 
      <%= submit_tag("Search", :class=>"btn") %> 
      <% end %> 

      <div class="media" data-bind="foreach: tweetsArray"> 
       <%= image_tag('twitter-icon.svg', :class=>"tweet_img", :style=>"display:inline;") %> 
       <div class="media-body" style="display:inline;"> 
        <h4 class="media-heading" data-bind="text: user.screen_name" style="display:inline;"></h4> 
        <span data-bind="text:text" style="display:inline;"></span> <br /> 
        <span data-bind="text:'Created at '+created_at"></span> <br /> 
       </div> 
      </div> 

      <div class="pagination pagination-centered"> 
       <ul> 
        <li> 
         <a href="#">Prev</a> 
        </li> 
        <li> 
         <a href="#">1</a> 
        </li> 
        <li> 
         <a href="#">Next</a> 
        </li> 
       </ul> 
      </div> 

     </div> 
    </div> 
</div> 

<script> 
    var viewModel = new twitterResearch.TweetViewModel(); 
    ko.applyBindings(viewModel); 

    //TODO: notes to self, use custom binding for pagination along with a computed observable to determine where at in the list you are 

    //document.onReady callback function 
    $(function() { 
     $.getJSON('twitter', {}, function(data) { 
      viewModel.pushTweet(data); 
      console.log(data.user); 
     }); 
    }); 
</script> 

declare var $: any; 
declare var ko: any; 

module twitterResearch { 
    class Tweet { 
     text: string; 
     created_at: string; 
     coordinates: string; 
     user: string; 
     entities: string; 
     id: number; 
     id_str: string; 

     constructor(_text: string, _created_at: string, _coordinates: any, _user: any, 
        _entities: any, _id_str: string, _id: number){ 

      this.text = _text; 
      this.created_at = _created_at; 
      this.coordinates = _coordinates; 
      this.user = _user; 
      this.entities = _entities; 
      this.id_str = _id_str; 
      this.id = _id; 
     } 
    } 

    export class TweetViewModel{ 

     tweetsArray: any; 
     constructor() 
     { 
      this.tweetsArray = ko.observableArray([]); 
     } 

     //tweet is going to be the JSON tweet we return 
     //from the server 
     pushTweet(tweet) 
     { 
      var _tweet = new Tweet(tweet.text, tweet.created_at, tweet.coordinates, 
            tweet.user, tweet.entities, tweet.id_str, tweet.id); 
      this.tweetsArray.push(_tweet); 
      this.tweetsArray.valueHasMutated(); 
     } 
    } 
} 

उत्तर

40

पृष्ठांकन नॉकआउट के साथ बहुत सरल है। मैं व्यक्तिगत रूप से यह इस तरह से प्राप्त होगा:

  • अपने सभी तत्वों से युक्त एक observableArray है
  • एक नमूदार वर्तमान पृष्ठ (0 को प्रारंभ)
  • एक चर प्रति पृष्ठ
  • तत्वों की संख्या घोषित करता है युक्त है
  • एक गणना की है जो पृष्ठों की संख्या देता है, प्रति पृष्ठ तत्वों की संख्या और तत्वों की कुल संख्या के लिए गणना की जाती है।
  • अंत में, एक गणना की गई जो सभी तत्वों वाले सरणी को स्लाइस करती है।

यह देखते हुए कि अब आप एक ऐसा फ़ंक्शन जोड़ सकते हैं जो वर्तमान पृष्ठ में वृद्धि (अगली) या कमी (पिछला) हो।

var Model = function() { 
    var self = this; 
    this.all = ko.observableArray([]); 
    this.pageNumber = ko.observable(0); 
    this.nbPerPage = 25; 
    this.totalPages = ko.computed(function() { 
     var div = Math.floor(self.all().length/self.nbPerPage); 
     div += self.all().length % self.nbPerPage > 0 ? 1 : 0; 
     return div - 1; 
    }); 

    this.paginated = ko.computed(function() { 
     var first = self.pageNumber() * self.nbPerPage; 
     return self.all.slice(first, first + self.nbPerPage); 
    }); 

    this.hasPrevious = ko.computed(function() { 
     return self.pageNumber() !== 0; 
    }); 

    this.hasNext = ko.computed(function() { 
     return self.pageNumber() !== self.totalPages(); 
    }); 

    this.next = function() { 
     if(self.pageNumber() < self.totalPages()) { 
      self.pageNumber(self.pageNumber() + 1); 
     } 
    } 

    this.previous = function() { 
     if(self.pageNumber() != 0) { 
      self.pageNumber(self.pageNumber() - 1); 
     } 
    } 
} 

आप यहाँ एक सरल और पूर्ण उदाहरण मिल जाएगा:

यहां एक त्वरित उदाहरण है http://jsfiddle.net/LAbCv/ (थोड़ा गाड़ी हो सकता है, लेकिन यह विचार है)।

+5

यह बहुत अच्छा है .. धन्यवाद! मैंने इसे प्रत्येक पृष्ठ संख्या दिखाने के लिए विस्तारित किया है और उपयोगकर्ता को पृष्ठ 5 से पृष्ठ 5 पर क्लिक करने की अनुमति दी है। Http://jsfiddle.net/LAbCv/31/ –

+5

अंतिम छमाही पृष्ठ को सही तरीके से छोड़ देता है? 'Math.ceil'' Math.floor' की बजाय पृष्ठ गिनती कैल्क में होना चाहिए? संपादित करें: आह आप शेष/मॉड्यूलस को वापस जोड़ते हैं, मैं बस इसे बंद कर दूंगा और किया जाएगा। – MrYellow

+0

इस दृष्टिकोण से सावधान रहें यदि आप किसी ऐसे चीज़ के साथ काम कर रहे हैं जिसके पास एक बड़ा परिणाम सेट हो सकता है। परिणाम क्लाइंट पक्ष की पूरी सूची लोड करने और फिर जावास्क्रिप्ट में केवल पृष्ठ लोड करना अच्छा विचार नहीं है। बड़े परिणाम सेट के लिए, आपको किसी प्रकार का AJAX समाधान चाहिए जो केवल वर्तमान पृष्ठ के लिए आवश्यक डेटा लोड करता है। – Mir

1

मैंने थोड़ी JQuery प्लगइन (here) की मदद से पेजिनेशन बनाने के तरीके के बारे में विस्तृत स्पष्टीकरण के साथ एक ब्लॉग पोस्ट बनाया है।

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

5

असल में मैं एक वेबसाइट पर काम कर रहा हूं, जिसमें बहुत सी टेबल हैं (उनमें से अधिकांश को पेजिंग की आवश्यकता है)।
तो वास्तव में, पेजिंग के लिए मुझे पेजिंग के लिए कुछ reusable-component की आवश्यकता थी जिसमें मुझे पेजिंग की आवश्यकता है।
इसके अलावा, मुझे इस प्रश्न के स्वीकृत उत्तर में प्रदान की गई अधिक उन्नत सुविधाओं की आवश्यकता है।

इसलिए मैंने इस मुद्दे को हल करने के लिए अपना स्वयं का घटक विकसित किया, यहां यह है।

Now on Github

JsFiddle

और अधिक जानकारी के लिए, पढ़ना जारी (, यहां से नहीं, GitHub से कोड लेने के लिए विचार करें के रूप में GitHub कोड अद्यतन और के बाद से मैं वृद्धि की गई इसे यहां रखें)

जावास्क्रिप्ट

function PagingVM(options) { 
    var self = this; 

    self.PageSize = ko.observable(options.pageSize); 
    self.CurrentPage = ko.observable(1); 
    self.TotalCount = ko.observable(options.totalCount); 

    self.PageCount = ko.pureComputed(function() { 
     return Math.ceil(self.TotalCount()/self.PageSize()); 
    }); 

    self.SetCurrentPage = function (page) { 
     if (page < self.FirstPage) 
      page = self.FirstPage; 

     if (page > self.LastPage()) 
      page = self.LastPage(); 

     self.CurrentPage(page); 
    }; 

    self.FirstPage = 1; 
    self.LastPage = ko.pureComputed(function() { 
     return self.PageCount(); 
    }); 

    self.NextPage = ko.pureComputed(function() { 
     var next = self.CurrentPage() + 1; 
     if (next > self.LastPage()) 
      return null; 
     return next; 
    }); 

    self.PreviousPage = ko.pureComputed(function() { 
     var previous = self.CurrentPage() - 1; 
     if (previous < self.FirstPage) 
      return null; 
     return previous; 
    }); 

    self.NeedPaging = ko.pureComputed(function() { 
     return self.PageCount() > 1; 
    }); 

    self.NextPageActive = ko.pureComputed(function() { 
     return self.NextPage() != null; 
    }); 

    self.PreviousPageActive = ko.pureComputed(function() { 
     return self.PreviousPage() != null; 
    }); 

    self.LastPageActive = ko.pureComputed(function() { 
     return (self.LastPage() != self.CurrentPage()); 
    }); 

    self.FirstPageActive = ko.pureComputed(function() { 
     return (self.FirstPage != self.CurrentPage()); 
    }); 

    // this should be odd number always 
    var maxPageCount = 7; 

    self.generateAllPages = function() { 
     var pages = []; 
     for (var i = self.FirstPage; i <= self.LastPage() ; i++) 
      pages.push(i); 

     return pages; 
    }; 

    self.generateMaxPage = function() { 
     var current = self.CurrentPage(); 
     var pageCount = self.PageCount(); 
     var first = self.FirstPage; 

     var upperLimit = current + parseInt((maxPageCount - 1)/2); 
     var downLimit = current - parseInt((maxPageCount - 1)/2); 

     while (upperLimit > pageCount) { 
      upperLimit--; 
      if (downLimit > first) 
       downLimit--; 
     } 

     while (downLimit < first) { 
      downLimit++; 
      if (upperLimit < pageCount) 
       upperLimit++; 
     } 

     var pages = []; 
     for (var i = downLimit; i <= upperLimit; i++) { 
      pages.push(i); 
     } 
     return pages; 
    }; 

    self.GetPages = ko.pureComputed(function() { 
     self.CurrentPage(); 
     self.TotalCount(); 

     if (self.PageCount() <= maxPageCount) { 
      return ko.observableArray(self.generateAllPages()); 
     } else { 
      return ko.observableArray(self.generateMaxPage()); 
     } 
    }); 

    self.Update = function (e) { 
     self.TotalCount(e.TotalCount); 
     self.PageSize(e.PageSize); 
     self.SetCurrentPage(e.CurrentPage); 
    }; 

    self.GoToPage = function (page) { 
     if (page >= self.FirstPage && page <= self.LastPage()) 
      self.SetCurrentPage(page); 
    } 

    self.GoToFirst = function() { 
     self.SetCurrentPage(self.FirstPage); 
    }; 

    self.GoToPrevious = function() { 
     var previous = self.PreviousPage(); 
     if (previous != null) 
      self.SetCurrentPage(previous); 
    }; 

    self.GoToNext = function() { 
     var next = self.NextPage(); 
     if (next != null) 
      self.SetCurrentPage(next); 
    }; 

    self.GoToLast = function() { 
     self.SetCurrentPage(self.LastPage()); 
    }; 
} 

एचटीएमएल

<ul data-bind="visible: NeedPaging" class="pagination pagination-sm"> 
    <li data-bind="css: { disabled: !FirstPageActive() }"> 
     <a data-bind="click: GoToFirst">First</a> 
    </li> 
    <li data-bind="css: { disabled: !PreviousPageActive() }"> 
     <a data-bind="click: GoToPrevious">Previous</a> 
    </li> 

    <!-- ko foreach: GetPages() --> 
    <li data-bind="css: { active: $parent.CurrentPage() === $data }"> 
     <a data-bind="click: $parent.GoToPage, text: $data"></a> 
    </li> 
    <!-- /ko --> 

    <li data-bind="css: { disabled: !NextPageActive() }"> 
     <a data-bind="click: GoToNext">Next</a> 
    </li> 
    <li data-bind="css: { disabled: !LastPageActive() }"> 
     <a data-bind="click: GoToLast">Last</a> 
    </li> 
</ul> 

विशेषताएं

  1. दिखाएँ जरूरत
    पर जब सब (उदाहरण के लिए आइटम पर पेजिंग की कोई आवश्यकता नहीं है जो प्रदर्शित करने के लिए की जरूरत है पेज आकार से कम) तो HTML घटक डिस होगा दिखाई देते हैं।
    यह कथन data-bind="visible: NeedPaging" द्वारा स्थापित किया जाएगा।

  2. अक्षम जरूरत
    उदाहरण के लिए पर, आप पहले से ही अंतिम पृष्ठ, का चयन किया जाता है, तो क्यों last page या Next बटन दबाएँ करने के लिए उपलब्ध होना चाहिए?
    मैं इस से निपटने कर रहा हूँ और उस मामले में मैं निम्नलिखित बाध्यकारीdata-bind="css: { disabled: !PreviousPageActive() }"

  3. लगाने से उन बटन अक्षम कर रहा हूँ चयनित पेज
    एक विशेष वर्ग भेद (इस मामले active वर्ग कहा जाता है) में लागू किया जाता है चयनित पृष्ठ पर, उपयोगकर्ता को यह जानने के लिए कि वह कौन सा पृष्ठ अभी है।
    यह बाध्यकारी data-bind="css: { active: $parent.CurrentPage() === $data }"

  4. अंतिम & पहले
    पहली और आखिरी पेज पर जाकर स्थापित है भी इस के लिए समर्पित सरल बटन से उपलब्ध है। दिखाया गया बटन
    मान लीजिए आप पृष्ठों की एक बहुत कुछ है, उदाहरण के लिए के लिए

  5. सीमाएं, 1000 पृष्ठों, तो क्या होगा? क्या आप उन्हें उपयोगकर्ता के लिए प्रदर्शित करेंगे? बिल्कुल आपको वर्तमान पृष्ठ के अनुसार उनमें से केवल कुछ प्रदर्शित करना होगा। उदाहरण के लिए, चयनित पृष्ठ के बाद 3 पृष्ठ पहले और अन्य 3 पृष्ठ दिखा रहा है।
    यह मामला यहां संभाला कर दिया गया है <!-- ko foreach: GetPages() -->
    GetPages समारोह एक सरल एल्गोरिथ्म को लागू करने का निर्धारण करता है, तो हम सभी पृष्ठों (पृष्ठ संख्या सीमा है, जो आसानी से निर्धारित किया जा सकता है किया जा रहा है) दिखाने की जरूरत है, या बस से कुछ दिखाने के लिए करने के लिए बटन
    आप maxPageCount वैरिएबल
    के मान को बदलकर थ्रेसहोल्ड निर्धारित कर सकते हैं अभी मैंने इसे निम्नलिखित var maxPageCount = 7; के रूप में असाइन किया है जिसका अर्थ है कि उपयोगकर्ता के लिए 7 से अधिक बटन प्रदर्शित नहीं किए जा सकते हैं (चयनित पृष्ठ से पहले 3 और 3 के बाद चयनित पृष्ठ) और चयनित पृष्ठ स्वयं।

    आप सोच सकते हैं कि क्या वर्तमान पृष्ठ प्रदर्शित होने से पहले या के बाद पर्याप्त पृष्ठ नहीं थे? चिंता मत करो मैं एल्गोरिथ्म
    उदाहरण के लिए, यदि आप 11 pages वर्तमान selected page is 10 है और आप maxPageCount = 7 है और, फिर अगले पन्नों

    5,6,7,8,9,10(selected page),11

    इसलिए हम हमेशा maxPageCount stratifying दिखाया जाएगा में इस से निपटने रहा हूँ, पिछले उदाहरण में चयनित पृष्ठ से पहले 5 पृष्ठ और चयनित पृष्ठ के बाद केवल 1 पृष्ठ दिखा रहा है।

  6. चयनित पृष्ठ मान्यकरण
    CurrentPage नमूदार जो उपयोगकर्ता द्वारा चयनित पेज का निर्धारण के लिए सभी सेट आपरेशन, समारोह SetCurrentPage से गुजर रहा है। केवल इस फ़ंक्शन में हमने इस अवलोकन को सेट किया है, और जैसा कि आप कोड को देख सकते हैं, मान सेट करने से पहले हम यह सुनिश्चित करने के लिए सत्यापन ऑपरेशन करते हैं कि हम पृष्ठों के उपलब्ध पृष्ठ से आगे नहीं जाएंगे।

  7. पहले से ही स्वच्छ
    मैं केवल pureComputed नहीं computed गुणों का उपयोग, आप सफाई और उन गुणों के निपटान के साथ खुद को परेशान करने के लिए की जरूरत नहीं है जिसका मतलब है। हालांकि, जैसा कि आप नीचे दिए गए उदाहरण में देखेंगे, तो आप कुछ अन्य सदस्यता जो घटक ही

नोट के बाहर हैं के निपटान के लिए की जरूरत है 1
आपको लगता है कि मैं कुछ bootstrap उपयोग कर रहा हूँ देख सकते हैं इस घटक में कक्षाएं, यह मेरे लिए उपयुक्त है, लेकिन , ज़ाहिर है, आप बूटस्ट्रैप कक्षाओं के बजाय अपनी कक्षाओं का उपयोग कर सकते हैं।
बूटस्ट्रैप वर्ग है जो मैं यहां इस्तेमाल किया pagination, pagination-sm, active और disabled
उन्हें बदलने के रूप में आप की जरूरत स्वतंत्र महसूस कर रहे हैं।

नोट 2
तो मैं आप के लिए घटक शुरू की, यह है कि यह कैसे काम कर सकता देखने के लिए समय है।
आप इस घटक को अपने मुख्य व्यू मॉडेल में इस तरह एकीकृत करेंगे।

function MainVM() { 
    var self = this; 

    self.PagingComponent = ko.observable(new Paging({ 
     pageSize: 10,  // how many items you would show in one page 
     totalCount: 100, // how many ALL the items do you have. 
    })); 

    self.currentPageSubscription = self.PagingComponent().CurrentPage.subscribe(function (newPage) { 
     // here is the code which will be executed when the user changes the page. 
     // you can handle this in the way you need. 
     // for example, in my case, I am requesting the data from the server again by making an ajax request 
     // and then updating the component 

     var data = /*bring data from server , for example*/ 
     self.PagingComponent().Update({ 

      // we need to set this again, why? because we could apply some other search criteria in the bringing data from the server, 
      // so the total count of all the items could change, and this will affect the paging 
      TotalCount: data.TotalCount, 

      // in most cases we will not change the PageSize after we bring data from the server 
      // but the component allows us to do that. 
      PageSize: self.PagingComponent().PageSize(), 

      // use this statement for now as it is, or you have to made some modifications on the 'Update' function. 
      CurrentPage: self.PagingComponent().CurrentPage(), 
     }); 
    }); 

    self.dispose = function() { 
     // you need to dispose the manual created subscription, you have created before. 
     self.currentPageSubscription.dispose(); 
    } 
} 

इतना ही नहीं बल्कि, यकीन मत भूलना with binding की तरह इस

<div data-bind="with: PagingComponent()"> 
    <!-- put the component here --> 
</div> 

चियर्स के साथ अपने विशेष ViewModel के अनुसार एचटीएमएल घटक में बाध्यकारी बदलने, या रैप करने के लिए सभी घटक

1

यह प्रश्न अभी भी "नॉकआउट पेजिनेशन" के लिए शीर्ष खोजों में से एक है, इसलिए नॉकआउट एक्सटेंशन knockout-paging (git) उल्लेखनीय है।
यह ko.observableArray बढ़ाकर अंकन प्रदान करता है। यह अच्छी तरह से प्रलेखित और उपयोग करने में आसान है।
उपयोग उदाहरण here है।