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.
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?
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.
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>
I put the link in my post: https://laracasts.com/discuss/channels/laravel/need-to-combine-two-functions
That is the original post with code.
@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'
}
},
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
}
}
})
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 post more info on what is not working. If I'm supposed to guess then I might miss.
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.
What is sortedColumn from the this.sortedColumn = column?
That populates with the name of the column. If you select Status to sort, this.sortedColumn changes to status.
@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?
@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 Not able to get it to work at all: https://jsfiddle.net/ajsmith_codes/bk592cv6/11/#&togetherjs=1UBLnaMs6n
Can you explain the use-case? What changed compared to the working solution I've provided?
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?
@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.
@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 then without real project I have no idea what is causing the issue.
@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!
@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 register and use this link to join the conversation https://prvtmsg.com/invitations/215a5e3a-0d80-452f-9cd0-41870f269dbd and then post the invitation code.
@bugsysha Hopefully I did it right. :)
@ajsmith_codes but you didn't post here the invite code. I need that to add you to the conversation.
LOL, when you visit the link I've posted, https://prvtmsg.com/invitations/215a5e3a-0d80-452f-9cd0-41870f269dbd , on page you should see something like invitation code and it is something like UUID format. Post that UUID formatted code here so I can add you to the conversation.
Lol, sorry about that! Here it is: 50f999d1-6d76-4153-bfea-e889e91e7306
@ajsmith_codes now you are added to the conversation. Feel free to write there.
Please or to participate in this conversation.