We are going to do the search filter and sorting function.
Step1 – Sort function
We want to allow users can sort todo items. We are going to use knockout-sortable.js plug-in. It help us to accomplish this function.
index.html:
It is to bind “sortable: {data: todos()}” in ul element in to-do control.
PS : don’t forget to include knockout-sortable plug-in in index.html.
<div class="form-group" >
<ul id="todo-list" data-bind="sortable: {data: todos()}">
<li data-bind="css: { completed: completed, editing: editing }">
<div class="view">
<input class="todoCheckbox" data-bind="checked: completed" type="checkbox" >
<label data-bind="text: title, event: { dblclick: $root.editItem }, css: {textDecoration:completed()==true}" ></label>
<button class="close pull-right" data-bind="click: $root.remove">×</button>
</div>
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.saveEditing, escapeKey: $root.cancelEditing, selectAndFocus: editing, event: { blur: $root.saveEditing }">
</li>
</ul>
</div>
plugin in index.html :
<script type="text/javascript" src="js/libs/knockout-sortable.js"></script>
Step2 – Search and Filter function
Interface
![TodoListApp](/images/knockoutjs_2_1.png)
Search function: user can find to-do item by using key words
Filter function: It filtter to-do item by todo status(active and completed). We will use another plug-in - router.js so as to filter to-do items.
index.html:
plugin in index.html :
<script type="text/javascript" src="js/libs/director.js"></script>
Search & Sorting control:
<div class="row" data-bind="visible: completedCount() || remainingCount()" style=" margin-top: 8px;">
<div class="col-xs-5" style="padding-left: 0px;">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button"><span class="glyphicon glyphicon-search"></span></button>
</span>
<input type="search" class="form-control" placeholder="Search" data-bind="textInput: query" autocomplete="off">
</div>
</div>
<div class="col-xs-3 ">
<ul class="nav nav-pills" id="filters">
<li data-bind="css: { active: isActive('all') }">
<a data-bind="css: { selected: showMode() == 'all' }" href="#/all">All</a>
</li>
<li data-bind="css: { active: isActive('active') }">
<a data-bind="css: { selected: showMode() == 'active' }" href="#/active">Active</a>
</li>
<li data-bind="css: { active: isActive('completed') }">
<a data-bind="css: { selected: showMode() == 'completed' }" href="#/completed">Completed</a>
</li>
</ul>
</div>
<div class="col-xs-2" style=" margin-top: 8px;">
<span id="todo-count">
<strong data-bind="text: remainingCount">0</strong>
<span data-bind="text: getLabel(remainingCount)"></span> left
</span>
</div>
</div>
To-do control:
I achieve search and filter function by css attribute. If to-do item does not meet condition, it will be hided.
It is to bind $root.filteredTodos($data) in li element so as to check whether todo meet condition in filteredTodos function.
<div class="form-group" >
<ul id="todo-list" data-bind="sortable: {data: todos()}">
<li data-bind="css: { completed: completed, editing: editing },visible: $root.filteredTodos($data)">
<div class="view">
<input class="todoCheckbox" data-bind="checked: completed" type="checkbox" >
<label data-bind="text: title, event: { dblclick: $root.editItem }, css: {textDecoration:completed()==true}" ></label>
<button class="close pull-right" data-bind="click: $root.remove">×</button>
</div>
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.saveEditing, escapeKey: $root.cancelEditing, selectAndFocus: editing, event: { blur: $root.saveEditing }">
</li>
</ul>
</div>
App.js:
There are two steps in filteredTodos function.
The first step is achieve the filter function.
The Second step is achieve the search function.
this.filteredTodos = function(todo) {
var result = true;
switch(this.showMode()){
case 'active':
if(todo.completed() != false)
result = false;
break;
case 'completed':
if(todo.completed() != true)
result = false
break;
}
if(result){
var filter = this.query().toLowerCase();
if(!filter){
return true;
}
else{
return todo.title().toLowerCase().indexOf(filter) !== -1;
}
}else
{
return false;
}
};
In this step, It is to get filter argument by URL(Router).
Router({'/:filter': viewModel.showMode}).init();
When you finish , you can see the TodoApp as below .
PS: I have added some functions in demo. I hope you can study these but I will not explain how to made.
The complete working demo can be found here .
##Building a Todo app with Knockout.js (1) - A simple todo list
##Building a Todo app with Knockout.js (2) - Filter、Search and Sortable function