0

I am using Vuetify 2.

I have custom filters for both a table and one of its columns, like this

https://codepen.io/hobbeschild/pen/zYJMjVY?editors=101

I cannot use the table search to find something in the column that has its own filter, because that column value is excluded from the table filter method. I feel that you should be able to search for "159" and get the first row. As well as using the calorie filter. Even if you extend the calorie filter to do a text search as well as its "less than" search, the false coming back from the table filter (because calories column is excluded) overrides the true from the column filter.

Any idea how to make the generic search read the calories column as well?

EDIT TO REPHRASE THE QUESTION

I want to put 159 in the Search box and see the row with 159 calories. I know I can use the Calorie filter for calories, and the Search box for names. I want to use the Search box for Calories (as well as the Calorie filter).

HTML:

<div id="app">
  <v-app id="inspire">
    <div>
      <v-data-table
        :headers="headers"
        :items="desserts"
        item-key="name"
        class="elevation-1"
        :search="search"
        :custom-filter="filterOnlyCapsText"
      >
        <template v-slot:top>
          <v-text-field
            v-model="search"
            label="Search"
            class="mx-4"
          ></v-text-field>
        </template>
        <template v-slot:body.append>
          <tr>
            <td></td>
            <td>
              <v-text-field
                v-model="calories"
                type="number"
                label="Less than"
              ></v-text-field>
            </td>
            <td colspan="4"></td>
          </tr>
        </template>
      </v-data-table>
    </div>
  </v-app>
</div>

JS:

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data () {
    return {
      search: '',
      calories: '',
      desserts: [
        {
          name: 'Frozen Yogurt',
          calories: 159,
          fat: 6.0,
          carbs: 24,
          protein: 4.0,
          iron: 1,
        },
        {
          name: 'Ice cream sandwich',
          calories: 237,
          fat: 9.0,
          carbs: 37,
          protein: 4.3,
          iron: 1,
        },
        {
          name: 'Eclair',
          calories: 262,
          fat: 16.0,
          carbs: 23,
          protein: 6.0,
          iron: 7,
        },
        {
          name: 'Cupcake',
          calories: 305,
          fat: 3.7,
          carbs: 67,
          protein: 4.3,
          iron: 8,
        },
        {
          name: 'Gingerbread',
          calories: 356,
          fat: 16.0,
          carbs: 49,
          protein: 3.9,
          iron: 16,
        },
        {
          name: 'Jelly bean',
          calories: 375,
          fat: 0.0,
          carbs: 94,
          protein: 0.0,
          iron: 0,
        },
        {
          name: 'Lollipop',
          calories: 392,
          fat: 0.2,
          carbs: 98,
          protein: 0,
          iron: 2,
        },
        {
          name: 'Honeycomb',
          calories: 408,
          fat: 3.2,
          carbs: 87,
          protein: 6.5,
          iron: 45,
        },
        {
          name: 'Donut',
          calories: 452,
          fat: 25.0,
          carbs: 51,
          protein: 4.9,
          iron: 22,
        },
        {
          name: 'KitKat',
          calories: 518,
          fat: 26.0,
          carbs: 65,
          protein: 7,
          iron: 6,
        },
      ],
    }
  },
  computed: {
    headers () {
      return [
        {
          text: 'Dessert (100g serving)',
          align: 'start',
          sortable: false,
          value: 'name',
        },
        {
          text: 'Calories',
          value: 'calories',
          filter: value => {
            if (!this.calories) return true

            return value < parseInt(this.calories)
          },
        },
        { text: 'Fat (g)', value: 'fat' },
        { text: 'Carbs (g)', value: 'carbs' },
        { text: 'Protein (g)', value: 'protein' },
        { text: 'Iron (%)', value: 'iron' },
      ]
    },
  },
  methods: {
    filterOnlyCapsText (value, search, item) {
      return value != null &&
        search != null &&
        value.toString().toLowerCase().indexOf(search) !== -1
    },
  },
})
hobbes_child
  • 131
  • 2
  • 12
  • For me it works just fine. For example, initially I see 10 rows in the table. Then I put `300` in the calories filter - and I see 3 rows. Then I type `fro` in the search field - and I see only one row. – IVO GELOV Mar 24 '23 at 13:33
  • @IVOGELOV I want to put 159 in the Search box and see the row with 159 calories. You are just using the Calorie filter for calories, and the Search box for names. I want to use the Search box for Calories (as well as the Calorie filter) – hobbes_child Mar 24 '23 at 13:38
  • 1
    I believe this is [this known issue](https://github.com/vuetifyjs/vuetify/issues/11600) with a fix planned for v2.7.0. I haven't tested it personally but according to the ticket the fix should be included already in v3.1.0 (caveat here being that `v-data-table` in v3 is not considered finished and is only available using the optional [Labs module](https://vuetifyjs.com/en/labs/introduction/)) – yoduh Mar 24 '23 at 13:42
  • @yoduh you misunderstand the question in the same way as IVO did. This bug report is not about doing a freetext search on Calories. It is about using the Search box on name. I want to use the Search box on Calories. I will try to clarify the question. – hobbes_child Mar 24 '23 at 13:57
  • I do understand your question and actually the github issue does match your question, but in the github example the custom column filter is on the "Desserts" text field and any attempt to search on a Dessert, e.g. "Eclair" in search box does not return correct result. It's the same issue you're having just explained with a different column. – yoduh Mar 24 '23 at 17:49
  • @yoduh the person has used the Calories filter, and then tried to do a freetext search on Dessert. The column with the custom filter is still Calories. They haven't got a custom filter on Dessert and then tried to do a freetext search on Dessert as well. That would be equivalent to my issue. – hobbes_child Mar 27 '23 at 08:11
  • There are two filters... One on Calories and one on Desserts. The Calorie filter was added as an example of a working filter when used with the v-slot and has nothing to do with the actual bug. The Dessert filter is specifically called out as the one that isn't working. See JS line 100 of the included [reproduction example](https://codepen.io/Ignigena/pen/dyYOmxj?editors=1010). – yoduh Mar 27 '23 at 15:17
  • @yoduh I apologise, you were right, I did not read thoroughly enough. I have done so now. I will look into v2.7.0 versus implementing the JS mentioned in there and below. Thank you. – hobbes_child Mar 30 '23 at 08:06

1 Answers1

1

This is the piece of code in Vuetify which performs the filtration:

  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
  })

As you can see - the result is a logical AND from both type of columns (those with custom filter and those without a filter). customFilter will be your filterOnlyCapsText function while defaultFilter is implemented like this

export function defaultFilter (value, search, item) {
  return value != null &&
    search != null &&
    typeof value !== 'boolean' &&
    value.toString().toLocaleLowerCase().indexOf(search.toLocaleLowerCase()) !== -1
}

A non-ideal solution seems to be to dynamically remove (undefine) the column filter from the column definition when the search term is non-empty.
Of course this will completely defeat the Calories filter - but at least it will obey the Search term.

A more complete solution would be to use your own filtration instead of the VDataTable filtration.

IVO GELOV
  • 13,496
  • 1
  • 17
  • 26