Vuetify Data Table: How are header filter functions applied

3.7k Views Asked by At

According to the Vuetify docs for custom filters in v-data-table, one can customize the filtering of a specific table column by supplying a filter property on header items.

In my application, I want to use this to customize filtering for a single column. For all other columns, I want to preserve the default string matching behavior.

As a jumping off point (see codepen), I have supplied a custom filter, that just returns true:

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data(){
    return {
      headers: [
        {
          text: 'Car Manufacturers',
          value: 'car',
          filter(){ return true }
        },
        {
          text: 'Country of Origin',
          value: 'country'
        }
      ],
      items: [
        { car: 'Honda', country: 'Japan' },
        { car: 'Audi', country: 'Germany' },
        { car: 'Ford', country: 'USA' }
      ],
      search: ''
    }
  },
})

and

<div id="app">
  <v-app>
    <v-container>
      <v-text-field
        label="Search"
        v-model="search"
      >
      </v-text-field>
      <v-data-table
        :headers="headers"
        :items="items"
        :search="search"
      >
      </v-data-table>
    </v-container>
  </v-app>
</div>

I would now have expected, that the filter on column car matches all rows and therefore the entire table is shown, no matter what search string I enter.

What I observe is, that the table is still filtered, but only by column country.

Conversely, when I change my filter to return false, an empty table is shown. I would then have expected, that the table is filtered only by column country.

How are the headers filters applied? Or, more precisely:

For each row, how are the results of the respective column filters combined to yield a filter result for the entire row?

2

There are 2 best solutions below

0
On

After some digging, I found this answer within a bug report on v-data-table filtering.

I still don't understand the thinking behind this, but apparently, custom column filters are handled differently than columns without custom filters:

Rows match, if (1) they match every() specified custom column filter and (2) they match some() default filter (i.e. contain search string).

The matching code in Vuetify seems to be this:

  return items.filter(item => {
    // Headers with custom filters are evaluated whether or not a search term has been provided.
    // We need to match every filter to be included in the results.
    const matchesColumnFilters = headersWithCustomFilters.every(filterFn(item, search, defaultFilter))

    // Headers without custom filters are only filtered by the `search` property if it is defined.
    // We only need a single column to match the search term to be included in the results.
    const matchesSearchTerm = !search || headersWithoutCustomFilters.some(filterFn(item, search, customFilter))

    return matchesColumnFilters && matchesSearchTerm
  })
0
On

A little bit late, but for those who still have the problem, I had to add filter-mode="union" to my data table

const headers = [
  {
    key: 'lastName',
    title: 'lastName',
    filter: (value: string, query: string) => {
      const normalizedValue = normalizeString(value.toString())
      const normalizedQuery = normalizeString(query.toString())

      return normalizedValue.toLowerCase().includes(normalizedQuery.toLowerCase())
    },
  },
]


 <VDataTable
  :sort-by="sortBy"
  :headers="headers"
  :items="items"
  ...
  :search="search"
  filter-mode="union"
 <VDataTable

With this, my search works in addition to the specific filter on my column.