opensoul.org

Live search with knockout.js

June 23, 2011 code 4 min read

Knockout.js is an interesting take on building rich web applications. While I was initially turned off by the MVVM approach of embedding bindings in the view, it has grown on me after playing around with it for a few days. I look forward to experimenting with it on a larger application.

My first experimentation with knockout is to implement live search. Here is a demo of searching for beers by name:

How to build it —————

To start with, we just want to display our list of beers. Once we get that done, then we can start implementing the search. I used a hard-coded list for this example, but this could easily be the result of an API request.

var beers = [
  {name:"…", brewery:"…", style:"…"},
  // …
];

We need to tell knockout about these beers so we can bind them to the view.

var viewModel = {
  beers: ko.observableArray(beers)
};

ko.applyBindings(viewModel);

Displaying this list of beers is simple. We create our markup for the list, and use knockout’s template binding.

<ul data-bind="template: {name:'beer', foreach:beers}"></ul>


<script type="text/html" id="beer">
  <li>
    <strong data-bind="text: name"></strong>     <span data-bind="text: brewery"></span>     <span data-bind="text: style"></span>
  </li>
</script>

Now we should be able see our list of beers. Next let’s implement the search functionality, starting with an input field to search with.

<input placeholder="Search…" type="search" data-bind="value: query, valueUpdate: 'keyup'" autocomplete="off">

The data-bind attribute tells Knockout that we want to bind the value of this input field to a variable called query, and we want to update that value on keyup. We need to set up query as an observable attribute.

var viewModel = {
  // …

  query: ko.observable('')
}

Whenever the query attribute is changed, we want to perform our search and update our list of beers, so we subscribe to updates on query and call a search function.

var viewModel = {
  // …

  search: function(value) {
    // remove all the current beers, which removes them from the view
    viewModel.beers.removeAll();

    for(var x in beers) {
      if(beers[x].name.toLowerCase().indexOf(value.toLowerCase()) >= 0) {
        viewModel.beers.push(beers[x]);
      }
    }
  }
};

viewModel.query.subscribe(viewModel.search);

Our search function begins by removing all the beers from the array observed by knockout, then loops through our list of beers and does a simple search, adding each beer back to the knockout array if it matches, which in turn updates it in the view.

View the source on the demo to see all of the code in context.

This content is open source. Suggest Improvements.

@bkeepers

avatar of Brandon Keepers I am Brandon Keepers, and I work at GitHub on making Open Source more approachable, effective, and ubiquitous. I tend to think like an engineer, work like an artist, dream like an astronaut, love like a human, and sleep like a baby.