Reputation: 2345
I've been toying around with knockoutjs trying to create html tables that can be filtered and paged so far i've been able to create the filtering and paging separately but it seems like i can't find a way to combine the two together down i put two example of what i've achieved any help would be great thanks in advance :)
Knockout Filtering Example:
HTML:
<table id="tview" class="table table-bordered table-striped table-hover">
<thead>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
<tr>
<td>
<input type="number" data-bind="event: { keyup: FilterItems }" id="ID" class="form-control filter" placeholder="Filter By ID" />
</td>
<td>
<input type="text" data-bind="event: { keyup: FilterItems }" id="Name" class="form-control filter" placeholder="Filter By Name" />
</td>
</tr>
</thead>
<tbody data-bind="foreach: $root.FilteredItem">
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
</tbody>
</table>
Javascript:
var model = function () {
var self = this;
self.Item = ko.observableArray([]);
self.FilteredItem = ko.observableArray([]);
self.Filter = new Filter();
self.FilterItems = function (object, event) {
var currentFilter = event.currentTarget.id;
var currentValue = $("#" + currentFilter).val();
if (currentValue != "") {
if (self.Filter.ActiveList().indexOf(currentFilter) < 0) {
self.Filter[currentFilter](true);
self.Filter.ActiveList.push(currentFilter);
}
self.ApplyFilters();
} else {
self.Filter[currentFilter](false);
self.Filter.ActiveList.remove(currentFilter);
if (self.Filter.ActiveList().length == 0) {
self.FilteredItem(self.Item());
} else {
self.ApplyFilters();
}
}
};
self.ApplyFilters = function () {
var tempArray = self.Item();
self.Filter.ActiveList().forEach(function (item) {
var value = $("#" + item).val();
var FilterResult = [];
if (isNaN(value)) {
value = value.toLowerCase();
FilterResult = ko.utils.arrayFilter(tempArray, function (obj) {
return obj[item]().toLowerCase().indexOf(value) > -1;
});
} else {
FilterResult = ko.utils.arrayFilter(tempArray, function (obj) {
if (isNaN(obj[item]())) {
return obj[item]().toLowerCase().indexOf(value) > -1;
} else {
return obj[item]() == value;
}
});
}
tempArray = FilterResult;
self.FilteredItem(FilterResult);
});
};
};
var Item = function () {
var self = this;
self.ID = ko.observable();
self.Name = ko.observable();
};
var Filter = function () {
var self = this;
self.ActiveList = ko.observableArray([]);
self.ID = ko.observable(false);
self.Name = ko.observable(false);
};
var modelInstance = new model();
for (i = 0; i < 10; i++) {
var MyItem = new Item();
MyItem.ID(i);
MyItem.Name("Name" + i);
modelInstance.Item.push(MyItem);
MyItem = new Item();
MyItem.ID(i);
MyItem.Name("Name" + i+1);
modelInstance.Item.push(MyItem);
}
modelInstance.FilteredItem(modelInstance.Item());
ko.applyBindings(modelInstance);
Knockout Paging Example:
HTML:
<section data-bind="foreach: Pages">
<article data-bind="visible: $root.CurrentPage() == $data">
<table id="tview" class="table table-bordered table-striped table-hover">
<thead>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
</thead>
<tbody data-bind="foreach: $root.Item()[$data]">
<tr>
<td data-bind="text: ID"></td>
<td data-bind="text: Name"></td>
</tr>
</tbody>
</table>
</article>
</section>
<ul class="pagination" data-bind="foreach: Pages">
<li data-bind="attr: { id: 'Page' + $index(), 'class': $root.checkCurrentPage($data) }, click: $root.ChangePage"><a href="#" data-bind="text: $data"></a>
</li>
</ul>
Javascript:
var Model = function () {
var self = this;
self.Item = ko.observableArray([]);
self.CurrentPage = ko.observable(0);
self.Pages = ko.observableArray([]);
self.ChangePage = function (data, event) {
if (!$(event.currentTarget).hasClass("active")) {
$(".pagination li").removeClass("active");
self.CurrentPage(data);
}
};
self.checkCurrentPage = function (data) {
if (self.CurrentPage() == data) {
return "active";
}
};
};
var Item = function () {
var self = this;
self.ID = ko.observable();
self.Name = ko.observable();
};
var modelInstance = new Model();
function Chunk(Arr, ChunkSize) {
var Set = [];
var PageCount = 0;
for (var Page = 0; Page < Arr.length; Page += ChunkSize) {
var TempArr = Arr.slice(Page, Page + ChunkSize);
var ObservableItemArr = [];
TempArr.forEach(function (obj) {
ObservableItemArr.push(obj);
});
Set.push(ko.observableArray(ObservableItemArr));
modelInstance.Pages.push(PageCount);
PageCount++;
}
return Set;
}
var arr = [];
for (i = 0; i < 20; i++) {
var MyItem = new Item();
MyItem.ID(i);
MyItem.Name("Name" + i);
arr.push(MyItem);
MyItem = new Item();
MyItem.ID(i);
MyItem.Name("Name" + i+1);
arr.push(MyItem);
}
modelInstance.Item(Chunk(arr, 10));
ko.applyBindings(modelInstance);
Upvotes: 0
Views: 1217
Reputation: 17564
Here is a Quick fiddle I did with LinqJS
http://jsfiddle.net/rL6p4onw/2
The structure looks like this
ViewModel = function() {
var items = [];
for(var i = 0; i < 500; i++) {
items.push({ name: "Foo " + i });
}
this.items = Enumerable.From(items);
this.page = ko.observable(0);
this.pageSize = ko.observable(10);
this.filter = ko.observable();
this.filteredCount = ko.observable();
this.currentPage = ko.computed(this.getCurrentPage, this);
this.pages = ko.computed(this.getPages, this);
}
Relevant code for paging / filtering
getCurrentPage: function() {
var filter = this.filter();
var filtered = this.items
.Where(function(i) {
return filter == null || i.name.indexOf(filter) != -1;
});
this.filteredCount(filtered.Count());
return filtered
.Skip(this.page() * this.pageSize())
.Take(this.pageSize())
.ToArray();
}
The filter function can easily be modfied to be dynamic since javascript is dynamic
Upvotes: 3