0

My goal is to be able to sort DEST or ASC the table. To do this, in the array 'tableItems' I get unformatted numbers, which I format to have the dot for thousands and the comma for decimals with the 'numericValues' method. This method returns numeric data, but in strings.

numericValues() {
    const numberFormat = new Intl.NumberFormat('de');

    this.tableItems.forEach((item) => {
      for (const key in item) {
        if (typeof item[key] === 'number') {
          const formattedValue = numberFormat.format(item[key]);

          item[key] = formattedValue;
        }
      }
    });
 }

I would like to be able to sort the table these strings but as if they were numbers. To do this, I have added the line ':custom-sort="customSort"' in my template.

The problem of having added the 'customSort' method, is that sort no longer works in my table, when I click on the headers

So, I show what I have tried to do with the method I add in custom-sort:

This is my template:

<v-data-table
          :headers="tableHeaders"
          :items="tableItems"
          :items-per-page="18"
          :search="search"
          class="elevation-1"
          :style="getTableHeight()"
          :custom-sort="customSort"
></v-data-table>

This is my method customSort:

customSort(tableItems: any[], index: number, isDescending: boolean): any[] {
    return tableItems.sort((a, b) => {
      console.log(a)
      const valueA = a;
      const valueB = b;

      if (typeof valueA === 'string' && typeof valueB === 'string') {
        const numA = Number(valueA);
        const numB = Number(valueB);

        if (!isNaN(numA) && !isNaN(numB)) {
          return isDescending ? numB - numA : numA - numB;
        }
      }

      return isDescending ? String(valueB).localeCompare(valueA) : String(valueA).localeCompare(valueB);
    });
}

Can anyone give me some advice on what I am doing wrong?

  • Remove the custom sort and `v-data-table` will sort according to the primitive data type. If these are `Number` - then they will be sorted numerically. You should format the values in the template only - not in the raw data. Simply use the corresponding slot for the given column. – IVO GELOV Jun 20 '23 at 08:54
  • Yes. Probably I have to delete the method 'numericValues', it will works. But I need the dots in the thousands and comma in decimals. If I use 'numericValues' I have String, but I need numeric type. – Manuel Yerbes Jun 20 '23 at 09:25

2 Answers2

0

I finally solved it as follows:

In the <v-data-table> component I added a <template> tag to customize the appearance and formatting of the data in the table.

<v-data-table
    :headers="tableHeaders"
    :items="tableItems"
    :items-per-page="18"
    :search="search"
    class="elevation-1"
    :style="getTableHeight()"
        >
        <template
          v-for="(headerItem, index) in tableHeaders"
          v-slot:[`item.${headerItem.value}`]="{ item }"
        >
          {{ headerItem.formatter ? headerItem.formatter(item[headerItem.value]) : item[headerItem.value] }}
        </template>
</v-data-table>

Finally, the method where it loaded the headers, added the formatting.

loadTableHeaders() {
    let aliases = [];
    aliases = this.$store.state.informes.dataInformes.get('aliases')?.filter((item: any) => item.endpoint === this.config.sources).sort((a: any, b: any) => (a.order < b.order ? -1 : 1));
    if (!aliases) {
      aliases = this.$store.state.informes.dataInformes.get(this.config.sources); // FIXME: Ordenar headers cuando no existan aliases
    }
    aliases.forEach((item: any) => {
      if (item.alias !== 'Nivel Territorial') {
        if ((informesStore.state.nivTerr !== 'CC.AA' && informesStore.state.nivTerr !== 'Nacional')
          || ((informesStore.state.nivTerr === 'CC.AA' || informesStore.state.nivTerr === 'Nacional') && item.alias !== 'Ámbito superior')) {
            this.tableHeaders.push({ text: item.alias, value: item.indicator, formatter: this.formatNumericValues });
        }
      }
    });
  }

  formatNumericValues(value: any) {
    if (typeof value === 'number' && !isNaN(value)) {
      return new Intl.NumberFormat('de').format(value);
    } else {
      return value; // Devuelve el valor sin formato para casos no numéricos
    }
  }
0

There are several issues:

  • The types of customSort() does not match that of :custom-sort. Your index is declared as number, but it is actually a string array (sortBy), and your isDescending (sortDesc) is actually a boolean array. You could have just copied the declaration from the documentation...
  • You logged the variable, so you are probably aware that the input to sort() is the whole object, not just the value. So when you assign the whole object to valueA and valueB respectively, none of the following comparisons will work. You need to extract the values using the props in sortBy.
  • A number in a local format, like german 1.000,56, cannot be transformed back to a number with Number(), you either need to parse it back or, preferably, keep the original number somewhere on your object and fall back to it during sorting.
  • If you want to be able to sort by multiple values, you need to go through the sortBy array and compare each field until you get a non-zero value.
Moritz Ringler
  • 9,772
  • 9
  • 21
  • 34