Searching & Filtering

Large sets of data should usually support search.

Overview

HQ has a custom searching and filtering component that uses Knockout Components. See search_box.js for full documentation.

Usage

The best way to understand how to implement the search box widget is to see its use in HQ directly. The best sources for this are the Web Users and Mobile Workers pages. As you might notice, it's often the case that the search box component is used in combination with the pagination component.

For the Mobile Workers page, the key points are:

A Quick Example

Here is a quick example simulating the search box usage. Ideally, this searching should be done asynchronously, as this widget is most useful for larger data sets, and it would likely be inefficient store the whole dataset in memory. This is mainly to have a visual reference of the search box widget.

Note: The immediate parameter used in this example controls whether the widget searches on every key press or only when the user clicks the search button or presses enter.
HTML
<div id="js-search-box-example">
  <search-box
    data-apply-bindings="false"
    params="
      value: query,
      action: search,
      immediate: true,
      placeholder: 'Search...'
    "
  ></search-box>
  <ul
    class="list-group pt-3"
    data-bind="foreach: items"
  >
    <li
      class="list-group-item"
      data-bind="text: $data"
    ></li>
  </ul>
</div>
JS
import $ from 'jquery';
import ko from 'knockout';
import _ from 'underscore';
import 'hqwebapp/js/components/search_box';

var searchBoxExample = function () {
    var self = {};

    self.allItems = "alpha beta delta gamma epsilon omega chi".split(" ");
    self.items = ko.observableArray(self.allItems);

    self.query = ko.observable('');
    self.search = function (page) {      // eslint-disable-line no-unused-vars
        self.items(_.filter(self.allItems, function (item) { return item.indexOf(self.query()) !== -1; }));
    };

    return self;
};

$("#js-search-box-example").koApplyBindings(searchBoxExample());

Client-Side Only Search

In some cases we might only want to do client-side searches. This means that the entire data set is stored in browser memory, and we query that dataset without making additional calls to the server.

An example use case for this is the "Clean Case Data" modal that can be accessed from the Case Data page. In this page we use the search box widget to filter case properties.

Key points for this example are:

Note that this is an example referencing the search-box widget usage only. The UI for this feature as a whole should not be duplicated as a "best practice" and hopefully cleaned up in the future.