7

I have a functioning Knockout template for some pagination UI that works with a Knockout-based shared data grid. This template renders an HREF for each "page" of data in the grid.

The template works but it's klunky because if I fetch a lot of data, then I end up with dozens and dozens of navigation page links below the grid. Here's the current template:

<div class="idTemplate_ko_simpleGrid_pageLinks">
    <p>
        <span>Go to page:</span>
        <!-- ko foreach: ko.utils.range(0, maxPageIndex) -->
            <a href="javascript:void(0);"
               class="grid-pagination" 
               data-bind="text: $data + 1, click: function() { $root.currentPageIndex($data) }, css: { selected: $data == $root.currentPageIndex() }"></a>
        <!-- /ko -->
    </p>
</div>

The 'currentPageIndex' value is just a simple ko observable in the model:

this.currentPageIndex = ko.observable(0);

And 'maxPageIndex' is a computed observable in the model:

this.maxPageIndex = ko.computed(function () {
    return Math.ceil(ko.utils.unwrapObservable(this.filteredItems()).length / this.pageSize()) - 1;
}, this);

How can I modify the template and model to enable paging UI similar to StackOverflow?

For example:

prev 1 ... 3 4 5 6 7 ... 69 next

Armchair Bronco
  • 2,367
  • 4
  • 31
  • 44

3 Answers3

19

This is exactly the pager style I have been using for a while now.

I just finished extracting the pager functionality I used on several projects, into an extension to knockout and template by example.

See https://github.com/remcoros/ko.pager for the source and http://remcoros.github.com/ko.pager/example.html for a working example.

All computations and some convenient properties are provided by the 'Pager' class, which you can create and bind to. But an example working template is included.

See the source example.html for usage.

Remco Ros
  • 1,467
  • 15
  • 31
  • This fell off the radar for me. I ended up rolling my own very simple implementation similar to this version but without all the bling-bling coolness. I like what I see here, so I'm going to accept this as the answer even though it isn't the solution I used. When I have the time, I'll try to rip out my code and replace it with this code. Thanks! – Armchair Bronco Jan 04 '13 at 23:39
1

First thing I would do is look if there are any custom bindings or libraries out there that do this. If there are, create a custom binding that uses that library.

Back up plan - make your own custom binding. I'd make something like:

<div data-bind="pagination: { maxIndex: maxPageIndex(), numToShow: 7 }">
...
</div>

Then in my custom binding, do something like this:

ko.bindingHandlers.pagination = {
    update: function(element, valueAccessor) {
        if (valueAccessor().maxPageIndex > valueAccessor().numToShow) {
            // use jquery to loop and append new $("<a>") tags to $(element), using "1", then ... and a segment in the middle, followed by ... and the last index.
        }
        else {
            // loop over the regular amount.
        }
    }
};
Richard Rout
  • 1,296
  • 1
  • 15
  • 28
1

Im so nice so I made one for you in exactly two minutes :P (So it probably has bugs) Its based on the first pager i found which was jQuery pagination

http://jsfiddle.net/tymTz/2/

Anders
  • 17,306
  • 10
  • 76
  • 144
  • Looking at this now and trying to retrofit for my own grid. Looks great in jsfiddle. Thanks in advance. I'll report back when the transplant surgery is complete. – Armchair Bronco Aug 21 '12 at 16:55
  • I will, but I'd like to verify first that I'm actually able to do the conversion. My first attempt failed because I have multiple KO data models on the same page and am using the following syntax to wire things up: ko.applyBindings(myViewModel, $bindingTarget.get(0)); – Armchair Bronco Aug 21 '12 at 18:11
  • never seen that kind of usage of applyBindings, argument two should be a DOM element – Anders Aug 21 '12 at 18:33
  • The 2nd argument resolves to a DOM element (assuming that $bindingTarget is a valid jQuery object). For example: var $bindingTarget = $("#idMyBindingTarget"); If I then use: $bindingTarget.get(0) with ko.applyBindings(...), I can fine-tune which elements participate in Knockout's "data-bind" world. I my case, I have a single-page web application with literally dozens of different binding regions. Anyway, I'll be sure to mark this as the answer as soon as my surgery is done! :-) – Armchair Bronco Aug 21 '12 at 21:30
  • I ended up accepting the answer below as it is a very polished solution (albeit one that was submitted several months after this answer). – Armchair Bronco Jan 04 '13 at 23:40