Skip to content

Instantly share code, notes, and snippets.

@sphingu
Created April 16, 2014 13:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sphingu/9d008d5cbc7bec8ae8ff to your computer and use it in GitHub Desktop.
Save sphingu/9d008d5cbc7bec8ae8ff to your computer and use it in GitHub Desktop.
Knockout Custom Pagination
<div id="body">
<section class="content-wrapper main-content clear-fix" data-bind="with: personList" style="margin-top: 30px;">
<table>
<thead>
<tr>
<td>First Name</td>
<td>Last Name</td>
<td>Age</td>
</tr>
</thead>
<tbody data-bind="foreach: items">
<tr>
<td data-bind="text: FirstName"></td>
<td data-bind="text: LastName"></td>
<td data-bind="text: Age"></td>
</tr>
</tbody>
</table>
<div align="center">
<ul class="pagination">
<li><a href="#" data-bind="click: MoveFirst">««</a></li>
<li><a href="#" data-bind="click: MovePrev">«</a></li>
<li><span class="txt">Page <input style="width: 25px" type="text" data-bind="event: { blur: setCurrentPage }, value: page, valueUpdate: 'blur'" /> of <span data-bind="text: totalPages"></span></span></li>
<li><a href="#" data-bind="click: MoveNext">»</a></li>
<li><a href="#" data-bind="click: MoveLast">»»</a></li>
<li><span class="txt">Viewing <span data-bind="text:startingRecord"></span>- <span data-bind="text: endingRecord"></span> of <span data-bind="text: totalRowCount"></span></span></li>
</ul>
</div>
</section>
</div>
<script>
$(document).ready(function () {
var personViewModel = new PersonViewModel();
ko.applyBindings(personViewModel, document.getElementById('body'));
});
</script>
<style>
ul.pagination {
display: inline-block;
}
ul.pagination li {
display: inline;
}
ul.pagination li a, ul.pagination li span.txt {
padding: 2px 10px;
border: 1px solid #ddd;
background: aliceblue;
border-radius:2px;
}
ul.pagination li span.txt input {
text-align:center;
}
ul.pagination li a {
color:black;
text-decoration: none;
}
ul.pagination li a:hover {
background:#ddd;
text-decoration: underline;
}
</style>
/// <reference path="jquery.d.ts" />
/// <reference path="knockout.d.ts" />
/// <reference path="knockout.validation.d.ts" />
class PagedArray {
public items: KnockoutObservableArray<any>;
public totalRowCount: KnockoutObservable<number>;
public totalPages: KnockoutObservable<number>;
public pageIndex: KnockoutObservable<number>;
public page: KnockoutObservable<number>;
public pageSize: KnockoutObservable<number>;
public startingRecord: KnockoutComputed<number>;
public endingRecord: KnockoutComputed<number>;
//public pages: KnockoutComputed<number[]>;
//TODO : add Filter and Sorting Variables
public canMoveFirst: KnockoutComputed<boolean>;
public canMovePrev: KnockoutComputed<boolean>;
public canMoveNext: KnockoutComputed<boolean>;
public canMoveLast: KnockoutComputed<boolean>;
public MoveFirst: () => void;
public MovePrev: () => void;
public MoveNext: () => void;
public MoveLast: () => void;
public setCurrentPage: () => void;
public load: (success: any, fail: any) => void;
private reload: (success: (any, totalRowCount: number) => any, fail: (any) => any) => void;
private loader: (pageIndex: number, pageSize: number, success: (any, totalCount: number) => any, fail: (any) => any) => void;
constructor(loader: (pageIndex: number, pageSize: number, success: (any, totalRowCount: number) => any, fail: (any) => any) => void, pageSize) {
var self = this;
self.loader = loader;
self.pageIndex = ko.observable(0).extend({ notify: 'always' });
self.page = ko.observable(1);
self.pageIndex.subscribe(function () {
self.page(self.pageIndex() + 1);
})
self.pageSize = ko.observable(pageSize || 10);
self.items = ko.observableArray([]);
self.totalRowCount = ko.observable<number>(0);
self.totalPages = ko.computed(function () {
return Math.ceil(self.totalRowCount() / self.pageSize());
});
self.startingRecord = ko.computed(function () {
return self.pageIndex() * self.pageSize() + 1;
});
self.endingRecord = ko.computed(function () {
return Math.min(self.page() * self.pageSize(), self.totalRowCount());
});
/*self.pages = ko.computed(function () {
var pageSlide = 2;
var pageCount = self.totalPages();
var pageFrom = Math.max(1, +self.page() - pageSlide);
var pageTo = Math.min(pageCount, +self.page() + pageSlide);
pageFrom = Math.max(1, Math.min(pageTo - (2 * pageSlide), pageFrom));
pageTo = Math.min(pageCount, Math.max(pageFrom + (2 * pageSlide), pageTo));
var data = [];
for (var i = pageFrom; i <= pageTo; i++) {
data.push(i);
}
return data;
});*/
/*<!--ko foreach: pages-- >
<!--ko if:$data == $parent.page()-- >
<li class="active" ><a href = "#" data - bind = "text: $data" ></a></li >
<!-- / ko-- >
<!--ko if:$data != $parent.page()-- >
<li><a href = "#" data - bind = "text: $data, click: function(){ $parent.page($data); $parent.setCurrentPage(); } " ></a></li >
<!-- / ko-- >
<!-- / ko-- >*/
self.canMoveNext = ko.computed(function () {
return self.page() != self.totalPages();
});
self.canMovePrev = ko.computed(function () {
return self.page() != 1;
});
self.canMoveFirst = ko.computed(function () {
return self.canMovePrev();
});
self.canMoveLast = ko.computed(function () {
return self.canMoveNext();
});
self.MoveNext = () => {
if (self.canMoveNext()) {
self.pageIndex(self.pageIndex() + 1);
self.reload(null, null);
}
};
self.MovePrev = () => {
if (self.canMovePrev()) {
self.pageIndex(self.pageIndex() - 1);
self.reload(null, null);
}
};
self.MoveLast = () => {
if (self.canMoveLast()) {
self.pageIndex(self.totalPages() - 1);
self.reload(null, null);
}
};
self.MoveFirst = () => {
if (self.canMoveFirst()) {
self.pageIndex(0);
self.reload(null, null);
}
};
//set page Index from page variable and reload data
self.setCurrentPage = () => {
if (isNaN(self.page())) {
self.page(self.pageIndex() + 1);
return;
}
var currentPage = +self.page();
self.page(currentPage);
//return if given page is already current page
if (currentPage == self.pageIndex() + 1) {
return;
}
if (currentPage <= 1) {
self.pageIndex(0);
self.reload(null, null);
}
else if (currentPage >= self.totalPages()) {
self.pageIndex(self.totalPages() - 1);
self.reload(null, null);
}
else {
self.pageIndex(currentPage - 1);
self.reload(null, null);
}
};
self.load = (success, fail) => {
self.pageIndex(0);
self.reload(success, fail);
};
self.reload = (success: (any, totalRowCount: number) => any, fail: (any) => any) => {
self.loader(self.pageIndex(), self.pageSize(),
function (data, totalRowCount) {
self.totalRowCount(totalRowCount);
self.items(data);
if (success) {
success(data, totalRowCount);
}
}, function (error) {
if (fail) { fail(error); }
else { alert(error.errorText || "Error"); }
});
};
}
}
public class PersonModel
{
public PersonModel(List<Person> persons,int count)
{
this.Persons = persons;
this.TotalCount = count;
}
public List<Person> Persons { get; set; }
public int TotalCount { get; set; }
}
public class Person
{
public Person(int id, string firstName, string lastName, int age)
{
this.Id = id;
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class PersonController : ApiController
{
private List<Person> _personList;
public List<Person> PersonList { get { return _personList; } }
public PersonController()
{
_personList = new List<Person>();
for (int i = 1; i < 1000; i++)
{
_personList.Add(new Person(i, "Sumit " + i, "Hingu " + i, i + 10));
}
}
// GET api/person
public PersonModel Get(int pageSize, int pageIndex)
{
PersonModel model = new PersonModel(PersonList.Skip(pageSize * pageIndex).Take(pageSize).ToList(),PersonList.Count);
return model;
}
}
/// <reference path="PagedArray.ts" />
/// <reference path="jquery.d.ts" />
/// <reference path="knockout.d.ts" />
/// <reference path="knockout.validation.d.ts" />
class PersonViewModel {
personList: PagedArray;
constructor() {
var self = this;
self.personList = new PagedArray((pageIndex, pageSize, success, fail) => {
$.ajax("/api/person", {
cache: false,
type: 'GET',
data: { pageIndex: pageIndex, pageSize: pageSize }
}).done(function (data) {
success(data.Persons, data.TotalCount);
}).fail(function (error) {
alert('Error Occured');
});
}, 7);
self.personList.load(null, null);
}
}
@sphingu
Copy link
Author

sphingu commented May 16, 2014

Two Services
GetItems(pageSize,pageIndex): items
GetTotalItems: totalCount

Page Size: [ ] Page 1 of 20 << < max five pages > >> Total Records

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment