Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ajsmith_codes's avatar

Filter and sort data using vue component.

In a previous post of mine, it was suggested that I post what I want to do vs posting all of my current code. If you wish to see that code: https://laracasts.com/discuss/channels/laravel/need-to-combine-two-functions

I'm using vue to show a list of Sales Orders. I have set up a filter/search. Let's say I search by ship date. After it brings results back, I would like to be able to sort the results by clicking on the column heading. It would then sort by date ascending. Another click would sort by descending.

What would be the best way to do this?

0 likes
27 replies
bugsysha's avatar

Just have a property on that component that will have the sort direction. First it is equal to unchanged, then when you first click on it you make it asc and then another click you change it to desc. Also when you click on another column it will go back to unchanged.

ajsmith_codes's avatar

Do you have some sample code for how to sort inside a component? I have only found a few tutorials on that and they send a request to sort.

bugsysha's avatar

It is better to show what you got so we can expand on that.

<template>
  <!--other html-->
  <button @click="changeSort('titleOfTheColumn')">Title Of The Column</button>
  <!--other html-->
</template>

<script>
export default {
  data() {
    return {
      selectedColumn: 'none',
      sortDirection: 'unchanged',
      listOfObjectsThatApiReturned: []
    }
  },
  computed: {
    listOfSortedObjects() {
      if (this.sortDirection === 'unchanged') return this.listOfObjectsThatApiReturned

      return this.listOfObjectsThatApiReturned.sort((a, b) => {
        if (this.sortDirection === 'asc') return a - b;

        return b - a;
      })
    }
  },
  methods: {
    changeSort(nameOfTheColumn) {
      if (nameOfTheColumn === this.selectedColumn && this.sortDirection === 'unchanged') {
        this.sortDirection = 'asc'
      }
      if (nameOfTheColumn === this.selectedColumn && this.sortDirection === 'asc') {
        this.sortDirection = 'desc'
      }
      if (nameOfTheColumn === this.selectedColumn && this.sortDirection === 'desc') {
        this.sortDirection = 'unchanged'
      }
      if (nameOfTheColumn !== this.selectedColumn) { // this if statement is not required
        this.selectedColumn = nameOfTheColumn
      }
    }
  }
}
</script>
ajsmith_codes's avatar

@bugsysha I think I'm really close. I have taken your code and modified it to match my variables and current structure. I can get the sortOrder to change, but the data doesn't move.

Here is what I have:

<th v-for="column in columns"
                                :key="column"
                                @click="sortByColumn(column)"
                                class="table-head text-center">

                                <span
                                    v-if="column==='number'">
                                    <a href="#"
                                       @click.prevent>
                                        SO#
                                    </a>
                                </span>

                                <span
                                    v-if="column==='revision'">
                                    <a href="#"
                                       @click.prevent>
                                        Rev
                                    </a>
                                </span>

                                <span
                                    v-if="column==='expedited'">
                                    <a href="#"
                                       @click.prevent>
                                      Expedited
                                    </a>
                                </span>

                                <span
                                    v-else-if="column === 'customer_po'">
                                    <a href="#"
                                       @click.prevent>
                                        Customer
                                        PO#
                                    </a>
                                </span>

                                <span
                                    v-else-if="column === 'requested_ship_date'">
                                    <a href="#"
                                       @click.prevent>
                                      Ship Date
                                    </a>
                                </span>

                                <span
                                    v-else-if="column === 'payment_type'">
                                    <a href="#"
                                       @click.prevent>
                                     Payment
                                    </a>
                                </span>

                                <span
                                    v-else-if="column === 'status'">
                                    <a href="#"
                                       @click.prevent>
                                     Status
                                    </a>
                                </span>

                                <span
                                    v-else-if="column === 'department_id'">
                                    <a href="#"
                                       @click.prevent>
                                     Dept
                                    </a>
                                </span>


                                <span
                                    v-if="column === sortedColumn">
                            <i v-if="sortOrder === 'asc' "
                               class="fas fa-arrow-up"></i>
                            <i v-else
                               class="fas fa-arrow-down"></i>
                                </span>
                            </th>

computed:

        listOfSortedObjects() {
              return this.tableData.sort((a, b) => {
                if (this.sortOrder === 'asc') return a - b;

                return b - a;
            })
        }
        sortByColumn(column) {
            if (column === this.sortedColumn) {
                this.sortOrder = (this.sortOrder === 'asc') ? 'desc' : 'asc'
            } else {
                this.sortedColumn = column
                this.sortOrder = 'asc'
            }
        },
bugsysha's avatar
bugsysha
Best Answer
Level 61

HTML

<div id="app">
  <div @click="changeStuff('order1')">Order 1</div>
  <div @click="changeStuff('order2')">Order 2</div>
  <hr>
  <ul>
    <li v-for="todo in sortedTodos">{{ todo.order1 }} {{ todo.order2 }} {{ todo.text }}</li>
  </ul>
</div>

JavaScript

new Vue({
  el: "#app",
  data: {
    column: 'order1',
    order: 'asc',
    todos: [
      { text: "Learn JavaScript", order1: 3, order2: 4 },
      { text: "Learn Vue", order1: 2, order2: 2 },
      { text: "Play around in JSFiddle", order1: 1, order2: 3 },
      { text: "Build something awesome", order1: 4, order2: 1 }
    ]
  },
  computed: {
    sortedTodos() {
      return [...this.todos].sort((a, b) => {
        return this.order === 'asc'
          ? a[this.column] - b[this.column]
          : b[this.column] - a[this.column]
      })
    }
  },
  methods: {
    changeStuff(column){
      if (column === this.column) {
        this.order = (this.order === 'asc') ? 'desc' : 'asc'
      } else {
        this.order = 'asc'
      }
      this.column = column
    }
  }
})
ajsmith_codes's avatar

@bugsysha

This code works for almost all of the columns I have, but there are a few that don't. I can't figure out why. Can you take a look? I don't want to create a new question if I can avoid it.

Below is the only code that changed:

```
    sortByColumn(column) {
        if (column === this.column) {
            this.order = (this.order === 'asc') ? 'desc' : 'asc'
        } else {
            this.order = 'asc'
        }
        this.column = column
        this.sortedColumn = column
    },
computed: {
    sortedOrders() {
        return [...this.tableData].sort((a, b) => {
            return this.order === 'asc'
                ? a[this.column] - b[this.column]
                : b[this.column] - a[this.column]
        })

    }

},
ajsmith_codes's avatar

@bugsysha

Sorry, I didn't mean to be confusing or leave anything out. :)

When I click on the columns, they sort either asc or desc. This works with the following columns: SO#, Expedited, Customer PO#, Payment, Dept.

These columns do not work: Rev, Ship Date, and Status.

I verified that asc/desc changes. I also verified that the value for "column" also changes.

Here is the very strange part: The first time I click on a column, it sorts, but the second time does not for the columns I listed.

bugsysha's avatar

What is sortedColumn from the this.sortedColumn = column?

ajsmith_codes's avatar

@bugsysha

That populates with the name of the column. If you select Status to sort, this.sortedColumn changes to status.

bugsysha's avatar

@ajsmith_codes sorry, but I do not see what the problem is from what you've described. Can you make a fiddle on jsfiddle.net?

ajsmith_codes's avatar

@bugsysha I've tried to make a fiddle before, but I can never get it to work. I am missing something when I transfer the code from my vue component. Do you have a tutorial you can recommend?

bugsysha's avatar

Can you explain the use-case? What changed compared to the working solution I've provided?

ajsmith_codes's avatar

@bugsysha

Instead of using the data in your 'todos' array, I used my existing array: tableData. tableData is populated by an axios get request.

In place of your list, I did this:

               <th v-for="column in columns"
                                :key="column"
                                @click="sortByColumn(column)"
                                class="table-head text-center">
                                <span
                                    v-if="column==='number'">
                                    <a href="#"
                                       @click.prevent>
                                        SO#
                                    </a>
                                </span>

                                <span
                                    v-if="column==='revision'">
                                    <a href="#"
                                       @click.prevent>
                                        Rev
                                    </a>
                                </span>

I don't use this:

 <div @click="changeStuff('order1')">Order 1</div>
  <div @click="changeStuff('order2')">Order 2</div>

The user clicks on the column name instead.

Does that help?

bugsysha's avatar

@ajsmith_codes in your initial question you wanted to sort numbers. I assume that now you want to sort strings also. If maybe that is the problem, then I advise you to check if the column is integer, and if so, then use the current function. And if it is a string then use string1.localCompare(string2) ES6 feature.

ajsmith_codes's avatar

@bugsysha I thought that might be the problem, but it's not. It will sort string, boolean, dates, etc. I can't find any pattern as to why it's not working. I'm trying to set up a fiddle still.

ajsmith_codes's avatar

@bugsysha I appreciate you trying. I'm not having luck with JS Fiddle, so I'm trying to upload to a staging site that I can share. I'll let you know if I get it uploaded. Thanks!

ajsmith_codes's avatar

@bugsysha I have it uploaded and it is working on the web. Is there a way I can send you a private message with login info?

ajsmith_codes's avatar

Lol, sorry about that! Here it is: 50f999d1-6d76-4153-bfea-e889e91e7306

Please or to participate in this conversation.