1
votes

I have a data structure here which i have divided into headers and the items. I am trying to apply a custom sort for which i have the logic down and i have created a method for it but i am not able to figure out how to apply that sort methods based on the name and grades individually. Here is a link to the codepen.

new Vue({
  el: '#app',
  data() {
    return {
      headers: [{
          text: 'Name',
          value: 'Name'
        },
        {
          text: 'Grades',
          value: 'grades'
        },
      ],
      labels: ['Andy', 'Max', 'John', 'Travis', 'Rick'],
      Grades: [99, 72, 66, 84, 91]
    }
  },
  computed: {
    tableItems() {
      let items = [],
        this.labels.forEach((label, i) => {
          let item = {}
          item.name = label
          item.grades = this.Grades[i]
          items.push(item)
          console.log(items)
        })
      return items
    }
  },
  methods: {
    sortBy(prop) {
      this.tableItems.sort((a, b) => a[prop] < b[prop] ? -1 : 1)
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
  <v-app id="inspire">
    <v-container>
      <v-layout>
        <v-flex v-for="(header, i) in headers" :key="header.text" xs4 py-1>
          <span>{{ header.text }}
                    <v-icon small @click="sortBy(this.labels)">arrow_upward</v-icon>  
                  </span>
        </v-flex>
        <v-layout v-for="item in tableItems" :key="item.name">
          <v-flex xs4 py-1>
            <span>{{ item.name }}</span>
          </v-flex>
          <v-flex xs4 py-1>
            <span>{{item.grades}}</span>
          </v-flex>

        </v-layout>
      </v-layout>
    </v-container>
  </v-app>
</div>

Now while keeping the data structure and everything the way it is, how can i make the method on the v-icon work for grades and name individually?

1

1 Answers

1
votes

Here are a few things I did to make it work.

  • Define a sortKey on the basis of which your data will be sorted
  • Pass the sortKey as an argument when you click on your span
  • When computing your tableItems use the sort key to sort your data

Look for the comments in the code below

<div id="app">
    <v-app id="inspire">
        <v-container>
        <v-layout>
            <v-flex v-for="header in headers" :key="header.text" xs4 py-1>
            <span>
                {{ header.text }}
                <v-icon small @click="sortBy(header.value)">arrow_upward</v-icon>
                ***** changed the value for name (from Name to name) ****
            </span>
            *** everything else is the same ***
        </v-layout>
        </v-container>
    </v-app>
</div>  

The script looks like this

    <script>
    export default {
      name: "app",
      data() {
        return {
          headers: [
            { text: "Name", value: "name" }, // changed this to name
            { text: "Grades", value: "grades" }
          ],
          labels: ["Andy", "Max", "John", "Travis", "Rick"],
          Grades: [99, 72, 66, 84, 91],
          sortKey: "" // added a sortKey,
        };
      },
      computed: {
        tableItems() {
          let retVal = this.labels.map((label, i) => {
            return {
              name: label,
              grades: this.Grades[i]
            };
          });
          // if there is a sortKey use that
          if (this.sortKey) {
            retVal.sort((a, b) =>
              a[this.sortKey] < b[this.sortKey] ? -1 : 1
            );
          }
          return retVal;
        }
      },
      methods: {
        sortBy(prop) {
          // assign sortKey here, this assignment will retrigger the computation
          this.sortKey = prop;
          console.log(prop);
        }
      }
    };
    </script>

************* EDIT *****************

add in a direction variable for your sorting order (1 is ascending, -1 is descending)

so your data would look like

data() {
    return {
        headers: [
            { text: "Name", value: "name" }, // changed this to name
            { text: "Grades", value: "grades" }
        ],
        labels: ["Andy", "Max", "John", "Travis", "Rick"],
        Grades: [99, 72, 66, 84, 91],
        sortKey: "" // added a sortKey,
        direction: 1 // for ascending order
    };
},

now in your program, if you are clicking on the same thing, you need to change your ascending or descending state, do that in your method

methods: {
    sortBy(prop) {
        // if the sortKey was prop to begin with
        if (this.sortKey === prop) {
            this.direction *= -1 // change direction to -ve or positive
        }
        // assign sortKey here, this assignment will retrigger the computation
        this.sortKey = prop;
        console.log(prop);
    }
}

Finally, use your direction in the sorting

computed: {
    tableItems() {
        let retVal = this.labels.map((label, i) => {
            return {
                name: label,
                grades: this.Grades[i]
            };
        });
        // if there is a sortKey use that
        if (this.sortKey) {
            retVal.sort((a, b) =>
                this.direction * // here multiply by the direction
                (a[this.sortKey] < b[this.sortKey] ? -1 : 1)
            );
        }
        return retVal;
    }
},

And You will be done