2
votes

The Vuetify.js data table component has built-in sorting, but it sorts according to the data in the model instead of the text that is display to the client.

In the example below, the raw values for 'age' (e.g. 'EIGHTEEN_TO_TWENTY') are converted to a more readable format (e.g. '18-20'). But since Vuetify sorts by the model, it sorts EIGHTEEN < FIFTEEN < TWENTYONE rather than 15 < 18 < 21. Is there a way to sort by the computed/displayed value?

Vue.use(Vuetify);
vue = new Vue({
    el: '#main',
    data: {
        members: [{name: 'Bob', age: 'FIFTEEN_TO_SEVENTEEN', id: 1},
          {name: 'Sue', age: 'EIGHTEEN_TO_TWENTY', id: 2},
          {name: 'Bill', age: 'TWENTYONE_TO_TWENTYFOUR', id: 3}],
        ageLabels: {FIFTEEN_TO_SEVENTEEN : '15-17',
          EIGHTEEN_TO_TWENTY : '18-20',
          TWENTYONE_TO_TWENTYFOUR : '21-24'},
        tableFields: [{value: 'name', text: 'Name'},
            {value: 'age', text: 'Age'},
            {value: 'id', text: 'ID'}]
    }
});
<!DOCTYPE html>
<html lang="en">
<head>
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
</head>
<body>
    <div id=main>
    <v-data-table :headers="tableFields" :items="members" data-app>
        <template v-slot:items="props">
            <td>{{ props.item.name }}</td>
            <td>{{ ageLabels[props.item.age] }}</td>
            <td>{{ props.item.id }}</td>
        </template>
    </v-data-table>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.8/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
</body>
1

1 Answers

2
votes

You can use Vue's computed property feature to change the default data model as per your need.

For that, the change in template would be:

<div id="main">
  <v-data-table :headers="tableFields" :items="formatMembers" disable-initial-sort data-app>
    <template v-slot:items="props">
      <td>{{ props.item.name }}</td>
      <td>{{ props.item.age }}</td>
      <td>{{ props.item.id }}</td>
    </template>
  </v-data-table>
</div>

Here I bind the :items to a computed property "formatMembers" instead of the original "members" in data. I added a new 'disable-initial-sort' property to disable vuetify's default initial sort which sorts the table by first column (in your case, it's the name column).

Then in the script, use computed property like this:

<script>
  Vue.use(Vuetify);
  let vue = new Vue({
    el: "#main",
    data: {
      members: [{
        name: "Bob",
        age: "FIFTEEN_TO_SEVENTEEN",
        id: 1
      }, {
        name: "Sue",
        age: "EIGHTEEN_TO_TWENTY",
        id: 2
      }, {
        name: "Bill",
        age: "TWENTYONE_TO_TWENTYFOUR",
        id: 3
      }],
      ageLabels: {
        FIFTEEN_TO_SEVENTEEN: "15-17",
        EIGHTEEN_TO_TWENTY: "18-20",
        TWENTYONE_TO_TWENTYFOUR: "21-24"
      },
      tableFields: [{
        value: "name",
        text: "Name"
      }, {
        value: "age",
        text: "Age"
      }, {
        value: "id",
        text: "ID"
      }]
    },
    computed: {
      formatMembers() {
        let newMembers = this.members.slice();
        newMembers.map((el, id) => (el.age = this.ageLabels[el.age]));
        return newMembers;
      }
    }
  });
</script>

Here is the working codesandbox link