<!DOCTYPE html>
<html>

<head>
  <script data-require="jquery@2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
  <link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
  <script data-require="bootstrap@*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
  <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
  <script type="text/javascript" src="//rawgit.com/rniemeyer/knockout-sortable/master/build/knockout-sortable.js"></script>
  <link href="style.css" rel="stylesheet" />
</head>

<body>
  <div class="container">
    <h1>Knockout.js Task List with Search and Filter, Random Tasks, In-place Editing, Sorting</h1>
    <a href="http://plnkr.co/ZmUclh?p=info">View the source on plunker</a>
    <hr/>

    <!-- New Task Form -->
    <div id="new-task" class="row">
      <div class="col-lg-12">
        <h2>Add New Task</h2>
        <form action="" data-bind="submit: addTask">
          <div class="input-group">
            <input type="text" class="form-control" placeholder="Task Name" data-bind="value: addTaskForm.taskName">
            <span class="input-group-btn">
              <button class="btn btn-primary" type="submit">Add Task</button>
            </span>
          </div>
        </form>
      </div>
    </div>

    <!-- Random Tasks Form -->
    <div id="random-tasks" class="row">
      <div class="col-lg-12">
        <h2>Add Random Task(s)</h2>
        <form action="" data-bind="submit: addRandomTasks">
          <div class="input-group">
            <input type="text" class="form-control" placeholder="N Tasks" data-bind="value: randomTaskForm.numberOfTasks">
            <span class="input-group-btn">
              <button class="btn btn-primary" type="submit">Generate Tasks</button>
            </span>
          </div>
        </form>
      </div>
    </div>

    <!-- Filter Tasks Form -->
    <div id="filter-tasks" class="row">
      <div class="col-lg-12">
        <h2>Existing Tasks (<span data-bind="text: tasks().length"></span>)</h2>
        <form action="" data-bind="submit: function() { return false; }">
          <div class="form-group">
            <input type="text" class="form-control" placeholder="Type to Filter Tasks" data-bind="value: filterTaskForm.taskName, valueUpdate: 'afterkeydown'">
          </div>
        </form>
      </div>
    </div>

    <!-- Tips and Sorting -->
    <div class="row">
      <div class="col-lg-6">
          <p>Click the task name to edit it.</p>
      </div>
      <div class="col-lg-6">
        <form action="" class="form-inline">
          <label for="sort-options">Sort Tasks</label>
          <select id="sort-options" class="form-control" data-bind="options: sortTaskForm.order, value: sortTaskForm.selectedOrder"></select>
        </form>
      </div>
    </div>

    <!-- Existing Task List -->
    <div id="existing-tasks" class="row">
      <div class="col-lg-12" id="existing-tasks">
        <ul data-bind="sortable: tasks">
          <li class="task" data-bind="css: { complete: isComplete() }, visible: isFiltered()">
            <div class="row">
              <div class="col-lg-6">
                <!-- Task name -->
                <span class="task-name" data-bind="text: $data.name, visible: !$data.isBeingEdited(), click: $data.edit"></span>
                <!-- Edit task form -->
                <form action="" data-bind="visible: $data.isBeingEdited(), submit: $data.edit">
                  <div class="input-group">
                    <input type="text" class="form-control" data-bind="value: name, hasFocus: $data.isBeingEdited()">
                    <span class="input-group-btn">
                      <button class="btn btn-success" type="submit">Save</button>
                    </span>
                  </div>
                </form>
              </div>
              <!-- Task buttons (complete, delete, up, down) -->
              <div class="col-lg-6">
                <div class="pull-right">
                  <span class="glyphicon glyphicon-ok" aria-hidden="true" data-bind="click: $data.complete"></span> &nbsp;
                  <span class="glyphicon glyphicon-remove" aria-hidden="true" data-bind="click: $parent.deleteTask"></span> &nbsp;
                  <span class="glyphicon glyphicon-arrow-up" aria-hidden="true" data-bind="click: $parent.upTask"></span> &nbsp;
                  <span class="glyphicon glyphicon-arrow-down" aria-hidden="true" data-bind="click: $parent.downTask"></span>
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>

  <script src="RandomTasks.js"></script>
  <script src="script.js"></script>
</body>

</html>
function ViewModel() {

  var self = this;

  /**
   * Public variables and functions
   */
  this.tasks = ko.observableArray();

  this.addTaskForm = {
    taskName: ko.observable()
  }
  this.filterTaskForm = {
    taskName: ko.observable()
  }
  this.randomTaskForm = {
    numberOfTasks: ko.observable()
  }

  this.sortTaskForm = {
    selectedOrder: ko.observable(),
    order: ko.observableArray([
      'By Name (A - Z)',
      'By Name (Z - A)'
    ])
  }

  this.addTask = addTask;
  this.deleteTask = deleteTask;
  this.upTask = upTask;
  this.downTask = downTask;
  this.addRandomTasks = addRandomTasks;

  /**
   * KO Bindings
   */
  this.filterTaskForm.taskName.subscribe(function(newValue) {
    filterTasks(newValue);
  });
  
  this.sortTaskForm.selectedOrder.subscribe(function(newValue) {
    sortTasks(newValue);
  })
  

  /**
   * Function definitions
   */
  function addTask(item, event) {
    if (self.addTaskForm.taskName().trim()) {
      self.tasks.push(new Task(self.addTaskForm.taskName()));
    }
  }

  function deleteTask(item, event) {
    self.tasks.remove(item);
  }

  function upTask(item, event) {
    var index = self.tasks.indexOf(item);
    if (index === 0) return;
    self.tasks.splice(index - 1, 2, self.tasks()[index], self.tasks()[index - 1]);
  }

  function downTask(item, event) {
    var index = self.tasks.indexOf(item);
    if (index === self.tasks().length - 1) return;
    self.tasks.splice(index, 2, self.tasks()[index + 1], self.tasks()[index]);
  }

  function addRandomTasks() {
    var n = self.randomTaskForm.numberOfTasks(),
      newTasks = [];
    for (var i = 0; i < n; i++) {
      newTasks.push(new Task(RandomTasks.generate()));
    }
    self.tasks(self.tasks().concat(newTasks));
  }

  function filterTasks(filter) {
    filter = filter.toLowerCase();
    self.tasks().forEach(function(task) {
      if (task.name().toLowerCase().indexOf(filter) > -1) {
        task.isFiltered(true);
      } else {
        task.isFiltered(false);
      }
    });
  }
  
  function sortTasks(order) {
    var sorted;
    sorted = self.tasks();
    if(order === "By Name (A - Z)") {
      sorted.sort(function sortAsc(a,b) {
        if(a.name() > b.name()) return 1;
        if(a.name() < b.name()) return -1;
        return 0;
      });
    } else if(order === 'By Name (Z - A)') {
      sorted.sort(function sortDesc(a,b) {
        if(a.name() > b.name()) return -1;
        if(a.name() < b.name()) return 1;
        return 0;
      });
    }
    self.tasks(sorted);
  }
}

function Task(name) {
  this.name = ko.observable(name);
  this.isComplete = ko.observable(false);
  this.isFiltered = ko.observable(true);
  this.isBeingEdited = ko.observable(false);
  this.complete = complete;
  this.edit = edit;

  function complete() {
    this.isComplete(!this.isComplete());
  }

  function edit() {
    this.isBeingEdited(!this.isBeingEdited())
  }
}

/**
 * Initialize the view model and generate some random tasks
 */
var vm = new ViewModel();
ko.applyBindings(vm);
for (var i = 0; i < 5; i++) {
  vm.tasks.push(new Task(RandomTasks.generate()));
}
/* Styles go here */

body {
  font-family: arial;
}

#existing-tasks ul {
    list-style-type: none;
    padding: 0px;
}

#existing-tasks li.task {
  background-color: LightCyan;
  padding: 10px;
  margin: 4px;
  border: 1px solid lightblue;
  border-radius: 4px;
  font-weight: bold;
}

#existing-tasks li.complete {
  background-color: lightgreen;
  border-color: green;
}

#existing-tasks li.task .glyphicon {
  cursor: pointer;
}

.task-name {
  cursor: pointer;
}
A simple task list with completion, deleting, and up/down buttons using Knockout.js.
var RandomTasks = {
  verbs: ["be","have","do","say","get","make","go","know","take","see","come","think","look","want","give","use","find","tell","ask","work","seem","feel","try","leave","call"],
  nouns: ["time","person","year","way","day","thing","man","world","life","hand","part","toy","eye","pet","place","work","week","case","point","government","company","number","group","problem","fact"],
  generate: generate
}

function generate(n) {
  var vlen = this.verbs.length,
      nlen = this.nouns.length,
      vrand =  Math.floor((Math.random() * vlen)),
      nrand =  Math.floor((Math.random() * nlen));
  return [this.verbs[vrand], 'the', this.nouns[nrand]].join(" ");
}