Stimulus.js Tutorial: How do I filter data in a list or table?

Let’s work off the previous Todo tutorial and add a way to filter those Todos using just Stimulus.

We will only need to work on the todos/index.html file, and to add one Javascript controller. This example will highlight how Stimulus enhances your server rendered HTML, without the need to build complicated constellations of Javascript objects.

Let’s begin by adding a div that will wrap our table, and a text input that we will use as a the filter source. The wrapper div will hold the filter controller. The input will call the filter#filter method on the controller, and it will supply the filter value from the target filter.source that we’ll use to hide our rows. Each of the tr elements is set as a filter.filterable target, and then we’ll set the value that we should filter at data-filter-key; in our case, the todo status and the title, all in lower case.

<div data-controller="filter">
  <input data-target="filter.source" 
              data-action="input->filter#filter" 
              type="text" 
              class="filter" 
              placeholder="Filter Todos" />
  <table>
    <% @todos.each do |todo| %>
      <tr data-target="filter.filterable" 
            data-filter-key='<%= "#{todo.completed ? 'done' : 'todo' } #{todo.title}".downcase %>'>
        <td>
           <input type="checkbox" <% if todo.completed %> checked <% end %> >
           <%= todo.title %>
        </td>
      </tr>
    <% end %>
  </table>
</div>

That’s all the html we need to update. Let’s move on to the javascript controller. Name your file filter_controller.js and setup the Stimulus controller template:

import { Controller } from "stimulus"

export default class extends Controller {

  }
} 

Let’s add the targets list, one for the input field source, and one for all the filterable rows:

  static targets = [ "source", "filterable" ]

And finally, let’s add the filter method:

  filter(event) {
    let lowerCaseFilterTerm = this.sourceTarget.value.toLowerCase()

    this.filterableTargets.forEach((el, i) => {
      let filterableKey =  el.getAttribute("data-filter-key")

      el.classList.toggle("filter--notFound", !filterableKey.includes( lowerCaseFilterTerm ) )
    })

The filter method will first pull the filter term from the source target, our input field on the index.html page. Then it will go through each of the filterableTargets, element by element, get the filter key that we set on each element, and toggle a class that will hide elements that don’t have the filter term in the filter key.

The CSS class that hides is element is here:

.filter--notFound {
  display: none;
}

Now you have a simple way to filter data on your page.

Feel free to leave comments or questions below.

Want To Learn More?

Try out some more of my Stimulus.js Tutorials.

2 thoughts on “Stimulus.js Tutorial: How do I filter data in a list or table?

  1. Hi there John , thanks for a great article, really helpful. Btw I think you should add `.toLowerCase()` before u do the string matching so that if the filterablekey has any uppercase charater, it would be able to match correctly.

    like this
    `let filterableKey = el.getAttribute(“data-filter-key”).toLowerCase()`

Leave a Reply