0
votes

I have a vue page (Main.vue) which renders a component from a separate vue file (Table.Vue). When I had all the logic baked into Main.vue, the free-form text filter was working fine. But now it lags on almost every character I type in, so I'm thinking there may be something wrong with my implementation.

The code I've posted below has been simplified (ie removed pagination and computed stuff) to show what I'm stuck on.

Table.vue:

  <!-- search bar -->
  <b-input-group>
    <b-form-input v-model="filter" type="search" placeholder="Type to Search"></b-form-input>
    <b-input-group-append>
      <b-button :disabled="!filter" @click="filter = ''">Clear</b-button>
    </b-input-group-append>
  </b-input-group>

  <b-table 
    :items="details" 
    :fields="fields" 
    :filter="filter"
    :current-page="currentPage"
    :per-page="perPage"
    @filtered="onFiltered"
  >
</b-container>

<script>

export default {
  name: 'Table',
  props: ['details'],
  data: function() {
    return {
      fields: [
        { key: 'ticket_number', sortable: true },
        { key: 'parent_id', label: 'Parent Ticket', sortable: true },
        { key: 'start', sortable: true, label: 'Start Date', formatter: (value) => { return moment(value, 'X').format('MM/DD/YYYY hh:mm:ss A') }},
  ],
  // free text filter
  filter: null
  }
},
  computed: {
  rows: function(){
    return this.details.length
  }
},
created: function () {
  this.filteredDetails = this.details
},
methods: {
  onFiltered(filteredItems) {
    // Trigger pagination to update the number of buttons/pages due to filtering
    this.totalRows = filteredItems.length
    this.currentPage = 1
    }
  }
}

Main.vue:

<template>
  <div v-if="details !== null">
      <custtable :details="filteredDetails"/>
      <br/>
  </div>
</template>

<script>

import { API } from '@/common/api.js'
import Table from '@/components/Table'

export default {
    name: 'Main',
    data: function() {
        return {
            details: [],
            filteredDetails: []
        }
    },
    components: {
        'custtable': Table
    }
}

</script>

So I'm wondering if the filter portion should even be in Table.vue: should it be in Main.vue? Where should the filter variable ideally be defined?

As stated, the functionality is there but it seems incredibly sluggish. The initial API call usually returns about 150 entries (JSON) so it's not a crazy amount of data.

I've been referencing the docs up to this point.

Any and all input is appreciated.

1

1 Answers

1
votes

If your table has a unique ID field (i.e. a primary key), specify that field key name via the primary-key prop. This will optimize how Vue re-renders the table.

i.e. if your items array has a field id that is guaranteed to be unique across all rows of data, then set the prop primary=key="id".

Filtering also needs to serialize each row's data into a single string of all the rows values, so it can take a bit of time if there are many fields (or deep nest fields).

Another option is to debouce your filter input. Rather than passing the v-model of your filter input directly to b-table's filter prop, store it in an intermediate variable, and only update the copy of the input's value sent to b-table after so many milliseconds of no keypress (input events).

What is happening in your case is that the filter process is running across the entire table every character entered, which is re-triggering Vue to re-render the entire table. Using a combination of primary-key and input debouncing should improve performance for you.