Using Events to Filter & Select Contacts in Grid

Learn how to filter the data shown in a table based on input using LitElement and MobX computed properties.

Now that you have the CRM data in the store, you can build the list view functionality.

This chapter covers:

  • listening to events on the search field,

  • creating a view-specific store,

  • using computed properties for filtering contacts,

  • handling grid selection.

Filtering Contacts in Grid

The grid now displays all the contacts in the system. You want it to display only contacts that match the search field input. You can achieve this using computed properties.

Create a new MobX store for the list view, frontend/views/list/list-view-store.ts.

import Contact from 'Frontend/generated/com/example/application/data/entity/Contact';
import ContactModel from 'Frontend/generated/com/example/application/data/entity/ContactModel';
import { crmStore } from 'Frontend/stores/app-store';
import { makeAutoObservable, observable } from 'mobx';

class ListViewStore {
  filterText = '';

  constructor() {
      { autoBind: true }

  updateFilter(filterText: string) {
    this.filterText = filterText;

  get filteredContacts() {
    const filter = new RegExp(this.filterText, 'i');
    const contacts = crmStore.contacts;
    return contacts.filter((contact) =>
      filter.test(`${contact.firstName} ${contact.lastName}`)

export const listViewStore = new ListViewStore();

The list view store follows the same pattern as the CRM store. It has one observable property, filterText, and one computed property, filteredContacts, which depends on the filterText and the crmStore.contacts array. Any time any of the dependencies of a computed property changes, the property is re-evaluated. The computed property returns an array of contacts that match the filterText.

Update the search field template in list view. Make sure to import listViewStore.

  placeholder="Filter by name"

Bind the value property (input text) to filterText. Add an event listener for the input event and bind it to the updateFilter() method.

Implement updateFilter() after the render() method:

updateFilter(e: { target: HTMLInputElement }) {

The method reads the input value though the event ( and calls the updateFilter() action. The action changes the filterText observable, which in turn updates the filteredContacts computed property.

The only thing needed to complete the filtering functionality is to change the grid template and bind to the computed filteredContacts property, instead of the array of all contacts.

<vaadin-grid class="grid h-full" .items=${listViewStore.filteredContacts}>

In your browser, try out the filtering functionality by typing something into the filter input box.

The grid has an active filter string

Selecting Contacts in Grid

The list view store should also track the selected contact. Start by adding a new observable property in the list view store:

selectedContact: Contact | null = null;

The selectedContact observable is either a Contact or null.

By default, MobX creates proxy objects for observable values. The downside of using proxy objects is that it breaks equality checks that Hilla Grid uses for tracking items. In this case, you aren’t interested in tracking changes to any of the properties of the selected contact, only in being notified when the contact changes. Update the constructor to override the observable behavior to observable.ref, which tracks the object reference without creating a proxy.

constructor() {
    { selectedContact: observable.ref },
    { autoBind: true }

Lastly, add a new action to the store to update the selected contact.

setSelectedContact(contact: Contact) {
  this.selectedContact = contact;

Update the grid template.

  class="grid h-full"

Grid supports multiple selection, so the selectedItems property needs to be expressed as a single-item array. Bind the active-item-changed event to a new method, handleGridSelection(). Implement the new method at the end of the class.

// vaadin-grid fires a null-event when initialized. Ignore it.
firstSelectionEvent = true;
handleGridSelection(e: CustomEvent) {
  if (this.firstSelectionEvent) {
    this.firstSelectionEvent = false;

The method calls the setSelectedContact() action with the value from the event, either a Contact or null. Hilla Grid fires an event with a null selection when it initializes, which you can ignore by adding a guard expression.

In your browser, you should now be able to click on a row and see that it gets highlighted. In the next chapter, you use the selected contact to populate the edit form.

A contact is highlighted in the grid