Seif
Seif

Reputation: 211

How to use vuetify's custom sort?

I'd like to use custom-sort in my data table. My goal is to sort the table DESC as opposed to the default ASC. But I don't know-how.

This is the start of my data table component:

  <v-data-table
  :headers="headers"
  :items="acts"
  hide-actions
  class="elevation-1"
  >
  <template slot="items" slot-scope="props">

    <td>{{ props.item.id }}</td>
    <td>{{ props.item.name }}</td>
    <td class="text-xs-center">{{ props.item.provider.id }}</td>
    <td class="text-xs-center">{{ props.item.category.name }}</td>
    <td class="text-xs-center">{{ props.item.budget }}</td>
    <td class="text-xs-center">{{ props.item.location.name }}</td>
    <td class="text-xs-center">{{ props.item.deets }}</td>
    <td class="text-xs-center">{{ props.item.keeping_it_100 }}</td>
    <td class="text-xs-center"><img width="50" height="50" :src="props.item.inspiration.inspiration"></td>
    <td class="justify-center layout px-0">....

And this is the script I'm using:

<script>
  export default {
    data () {
      return {

        dialog: false,
        customerSort: {
          isDescending: true,// I tried this? as the kabab format throws an error
        },
        headers: [
            { text: 'ID', value: 'id'},
            { text: 'Name', value: 'name' },  
            { text: 'Provider', value: 'provider' },
            { text: 'Category', value: 'category' },
            { text: 'Budget', value: 'budget' },
            { text: 'Country', value: 'location', sortable: true },
            { text: 'Keeping it 100%', value: 'keeping_it_100', sortable: false },
            { text: 'deets', value: 'deets', sortable: false },
            { text: 'inspiration', value: 'inspiration', sortable: false },
            { text: 'Cover', value: 'cover', sortable: false },
            { text: 'Actions', value: 'actions', sortable: false }
        ],

According to docs it is a function prop. But I haven't found an example on how to pass it.

This is a screenshot of the function...

Upvotes: 18

Views: 59131

Answers (6)

joergwork
joergwork

Reputation: 301

Although it's an old question ...

For special sorting of only one column, you could use the property sort in the headers array. See also https://vuetifyjs.com/en/api/v-data-table/#headers

Like so:

// in data ... 
headers: [
... 
{
    text: "Date",
    sortable: true,
    value: "date",
    sort: (a, b) => a.time_stamp - b.time_stamp
 },
 ...
]

use it like

<v-data-table
 :headers="headers"
...
>

Upvotes: 9

Ebrahim Karam
Ebrahim Karam

Reputation: 961

To Build on the response provided by bhaskar

I had to edit the last code sample to the following in order to work on vuetify 2.x. The code sorts the date columns by their epoch time which is stored under the time_stamp key. The code also allows the default sorting of numbers and strings (strings are sorted alphabetically)

        customSort(items, index, isDesc) {
        items.sort((a, b) => {
            if (index[0] == "date") {
                if (!isDesc[0]) {
                    return a.time_stamp - b.time_stamp;
                } else {
                    return b.time_stamp - a.time_stamp;
                }
            } else if (!(isNaN(a[index[0]]))) {
                if (!isDesc[0]) {
                    return (a[index[0]] - b[index[0]]);
                } else {
                    return (b[index[0]] - a[index[0]]);
                }

            } else {
                if (!isDesc[0]) {
                    return (a[index[0]] < b[index[0]]) ? -1 : 1;
                } else {
                    return (b[index[0]] < a[index[0]]) ? -1 : 1;
                }
            }
        });
        return items;
    }

Upvotes: 3

verunar
verunar

Reputation: 874

In vuetify 2 just use sortBy="date" and update: sort-desc

<v-data-table
  :headers="headers"
  :items="acts"
  :pagination.sync="pagination"
  sortBy="date"
  update: sort-desc
 >

Upvotes: 1

naffarn
naffarn

Reputation: 562

NOTE: the following answer is for Vuetify 1.5.x

A little late to the party here, if all you want to do is sort descending by a single field, then custom-sort it not what you want to use, you're better off using the :pagination.sync prop

Custom sort is used when you want to change the behaviour of the comparison function (e.g sorting based off the reverse or lowercase version of a string, or proper sorting of date strings in the format 'DD-MM-YYYY').

If you want to use the default descending functionality, use the :pagination.sync prop, like so:

<v-data-table
  :headers="headers"
  :items="acts"
  :pagination.sync="pagination"
>
    <template v-slot:items="props">...</template>
</v-data-table>

In your script, set pagination:

data () {
  return {
    pagination: {
      sortBy: 'id', // The field that you're sorting by
      descending: true
    }
  }
}

This specifies that you want the table to be initially sorted by descending id - id can be changed to any field name in the dataset.

It's worth noting that this only specifies the default behaviour, and if you have sorting enabled for your other headers, users can still sort the table by any field.

Upvotes: 5

Bhaskar
Bhaskar

Reputation: 1938

You can use a function like this-

customSort(items, index, isDesc) {
  items.sort((a, b) => {
    if (index === "date") {
      if (!isDesc) {
        return compare(a.date, b.date);
      } else {
        return compare(b.date, a.date);
      }
    }
  });
  return items;
}

Where the compare is a function which compares a.date and b.date and returns 1 or -1

isDesc is a variable passed by the table which tells in what order does the user want to sort it. If you want to sort in desc, just use !isDesc in the if-else condition

To use this in your template just use

<v-data-table
  :headers="headers"
  :items="Data"
  :custom-sort="customSort"
>
  <template slot="items" slot-scope="props">
    <td class="font-weight-black">{{ props.item.date }}</td>
    <td class="text-xs-right">{{ props.item.time }}</td>
    <td class="text-xs-right">{{ props.item.name }}</td>
  </template>
</v-data-table>

To make sure your other fields still work with the normal sort use

customSort(items, index, isDesc) {
      items.sort((a, b) => {
        if (index === "date") {
          if (!isDesc) {
            return dateHelp.compare(a.date, b.date);
          } else {
            return dateHelp.compare(b.date, a.date);
          }
        } else {
          if (!isDesc) {
            return a[index] < b[index] ? -1 : 1;
          } else {
            return b[index] < a[index] ? -1 : 1;
          }
        }
      });
      return items;
    }

Upvotes: 18

kuromoka
kuromoka

Reputation: 842

Based on this answer code about custom-filter, I tried using custom-sort.
Please refer to this answer if you apply it to your code.

By the following code, I have confirmed sorting when I click 'Calories' header.
My CodePen

new Vue({
    el: '#app',
    data() {
        return {
            food: [
                { name: 'Bakchoi', type: 'vegetable', calories: 100 },
                { name: 'Pork', type: 'meat', calories: 200 },
                { name: 'Chicken Thigh', type: 'meat', calories: 300 },
                { name: 'Watermelon', type: 'fruit', calories: 10 },
            ],
            headers: [
                { text: 'Name', align: 'left', value: 'name' },
                { text: 'Food Type', align: 'left', value: 'type' },
                { text: 'Calories', align: 'left', value: 'calories' },
            ],
            search: '',

        };
    },
    methods: {
        customSort(items, index, isDescending) {
          // The following is informations as far as I researched.
          // items: 'food' items
          // index: Enabled sort headers value. (black arrow status).
          // isDescending: Whether enabled sort headers is desc
          items.sort((a, b) => {
              if (index === 'calories') {
                  if (isDescending) {
                      return b.calories - a.calories;
                  } else {
                      return a.calories - b.calories;
                  }
              }
          });

          return items;
        }
    }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/vuetify.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons">

<div id="app">
    <v-app>
        <v-select
                label="Food Type"
                :items="['vegetable', 'meat', 'fruit']"
                v-model="search"
        ></v-select>

        <v-data-table
                :headers="headers"
                :items="food"
                :search="search"
                :custom-sort="customSort"
                hide-actions
        >
            <template slot="items" scope="{ item }">
                <td>{{ item.name }}</td>
                <td>{{ item.type }}</td>
                <td>{{ item.calories }}</td>
            </template>
        </v-data-table>
    </v-app>
</div>

Upvotes: 6

Related Questions