opensoul.org

Live search with knockout.js

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.

framework and javascript June 23, 2011

4 Comments

  1. Ryan Niemeyer Ryan Niemeyer June 23, 2011

    Hello- Glad that you are enjoying Knockout.  I wanted to offer an alternate implementation for you to look at: http://jsfiddle.net/rniemeyer/cCBqJ/

    Not drastically different, it just shows how you can use a dependentObservable that will get re-evaluated whenever your query changes.  

    I look forward to future posts on Knockout.js!

  2. Brandon Keepers Brandon Keepers June 23, 2011

    Ryan: awesome, thanks for chiming in! I wasn’t sure if I was doing it the knockout way, but was happy with how concise the code was anyway.

    I’ll update the post to use this method.

  3. Bhaarat Bhaarat June 24, 2011

    Very interesting. But what is the list of beer’s were to come from some database (more realistic)

  4. Brandon Keepers Brandon Keepers June 25, 2011

    Bhaarat: Knockout doesn’t really care how you get the list.  So you could easily update search function above with an Ajax call using jQuery or your library of choice, and when the results come back, append them to the array observed by knockout.

Post a Comment

Comments use textile. Anonymous comments will be deleted.

My name is Brandon Keepers. I like to build things, usually in Ruby or JavaScript. I work at GitHub and live in Holland, MI.

Popular Posts