How to sort computed values in a v-data-table - vue.js

I have a v-data-table from Vuetify in my Vue.js app.
The table has a column of computed values.
I wanna make that column sortable.
What do I have to do?
What I tried:
I was looking into the sort function of the v-data-table-header.
It offers: sort?: (a: any, b: any) => number.
However, when I define that function for my column the values in the column are still not sorted.
HTML:
<v-data-table
:headers='headers'
:items='items'
>
<template v-slot:item.complete='{ item }'>
<span v-if='!isComplete(item)' class='error--text'>not complete</span>
<span v-else>complete</span>
</template>
</v-data-table>
Script:
readonly headers: DataTableHeader[] = [
{
text: 'Completeness',
value: 'complete',
sort: (a, b) => {
console.log(a, b);
return 1;
}
},
];
items = [
{
name: "foo",
tasks: 3
},
{
name: "bar",
tasks: 42
}
]
isComplete(item: any): boolean {
return 12 <= item.tasks && item.tasks <= 50;
}
The order doesn't change when I enable sorting and the log says:
undefined undefined
undefined undefined
undefined undefined
...
What do I need to do to sort computed values?

I don't think you can sort computed data in a table unless the objects inside items array each have a field called complete with some value, because that's what the table is looking for to get the value (hence undefined).

Related

In vue, how do I filter a data object to only show values from the last 24 hours?

I have an array with some data objects that were created on various dates. I would like to only display the objects that were created within the last 24 hours.
I have tried to use moment for this, by using subtract on the date values, but it has no effect. Maybe someone here could come up with a suggestion.
Here are my computed properties. I use these because I am outputting the data in a bootstrap table, so the "key" represents the different values inside the object.
My table:
<b-card class="mt-4 mb-4">
<b-table
:items="tasks"
:fields="fields"
sort-desc
/>
</b-card>
My array (I am actually importing from a database, but for this question I will just write it manually) Please note I am just showing a single object here. In reality I have hundreds of objects
data: {
tasks: [
{ message: 'Foo' },
{ creationDateTime: '03-02-2022' },
{ isRead: false }
]
}
In my computed properties I then pass them to the table
computed: {
fields() {
return [
key: 'message',
label: 'message'),
sortable: true,
},
{
key: 'creationDateTime',
label: 'Date created',
formatter: date => moment(date).subtract(24, 'hours').locale(this.$i18n.locale).format('L'),
sortable: true,
},
{
key: 'isRead',
label: 'Has been read'),
sortable: true,
}
]
},
},
As I said, using subtract does not work. It still shows all objects in my database
I tried doing the reduction on the whole array as well, but I just get the error:
"TypeError: this.list.filter is not a function"
newTasks(){
if(this.tasks){
return moment(this.tasks.filter(task => !task.done)).subtract(24, 'hours')
}
}
I'm out of ideas.
In Moment, you can check if a date is within the last 24 hours with:
moment().diff(yourDate, 'hours') < 24
(note that future dates will also pass this check, but you can easily adjust it).
You can put this into your computed property:
newTasks(){
if(!this.tasks){
return []
}
return this.tasks.filter(task => !task.done && moment().diff(task.creationDateTime, 'hours') < 24)
}
And that's it, now newTasks should contain all tasks from the last 24 hours that are not done.

How to use two arrays in Vuetifyes v-autocomplete

I have two arrays, one with 7 boolean values representing the weekdays, and the other with the weekdays names and the value of which day of the week it represents, kind of index of weekdays (0 beeing sunday, and 6 beeing saturday)
This sample is from the ts file belonging to the vue file where the autocomplete is.
export const scheduleDays: TextValueViewModel[] = [
{ Text: "Mon", Value: 1},
{ Text: "Tue", Value: 2 },
{ Text: "Wed", Value: 3 },
{ Text: "Thu", Value: 4 },
{ Text: "Fri", Value: 5 },
{ Text: "Sat", Value: 6 },
{ Text: "Sun", Value: 0 }
];
This is from a view model I have containing this array with booleans representing the weekdays.
public readonly SelectedDays: boolean[] = [false,false,false,false,false,false,false];
I then have a autocomplete where I want to save the clicked checkboxes and that would be saved into the boolean array
<v-autocomplete
v-model="editedReleaseSchedule.ScheduleInterval.SelectedDays"
:items="scheduleDays"
:item-text="item => `${item.Text}`"
:item-value="item => `${item.Value}`"
:label="'ADMINISTRATION_RELEASE_SCHEDULE_DETAILS_SCHEDULED_DAYS' | translate('Selected days')"
:disabled="formDisabled"
:rules="[rules.required]"
outlined
hide-details
multiple
dense
/>
How can I make the clicked value of the weekday array beeing saved into the boolean array in the right index spot? And at the same time I want the correct checkboxes be checked in the autocomplete field.
The implemented auto complete in the interface
Using Vue 2 at my workplace, so no solution for vue 3 would work out for me.
I've tried to google if I can get the index of the v-autocomplete row and use that in item-value like:
editedReleaseSchedule.ScheduleInterval.SelectedDays[index]
but that does not seem possible. I've also tried different ways of filtering before using v-autocomplete, but I still want the whole list, not only the clicked (marked) once.
Use an intermediate model for the selectedValues, watch it, and map the selected values ([1,2,3...,0]) into the real model.
data: () => ({
selectedValues: [],
// ...
<v-autocomplete
v-model="selectedValues"
<!-- etc -->
watch: {
selectedValues(newValues) {
const allFalse = [false,false,false,false,false,false,false];
this.editedReleaseSchedule.ScheduleInterval.SelectedDays = allFalse;
newValues.forEach(value => {
// presumes sunday is the last index, the others are offset by +1
let j = value === 0 ? 6 : value-1;
this.editedReleaseSchedule.ScheduleInterval.SelectedDays[j] = true;
})
},

Vue + Element UI: (el-select) create new option and then put an customized object into data

In Vue2 I got Two el-select.
One is for selecting count,the other one is for name,
when you select the name it will save both name and price to data
<el-select
v-model="item"
value-key="name"
>
<el-option
v-for="(option,index) in OptionsArr"
:key="index"
:label="option.name"
:value="option"
>
{{option.name}}
</el-option>
OptionsArr
[
{
name: "apple" ,
price: 200
},
{
name: "orange" ,
price: 150
}
]
initial data
[
{
name:"",
price:0,
count:0
}
]
data when select apple
[
{
name:"apple",
price:200,
count:0
}
]
And now I want to let user create their own option so I add filterable, allow-create and default-first-option to this el-select
<el-select
v-model="item"
value-key="name"
filterable
allow-create
default-first-option
Now when I input "NewOption" to create an option, it just add a string to the data array, the data becomes:
[
"NewOption"
]
and I want to add a object to the array like this:
[
{
name:"NewOption",
price:0,
count:0
}
]
I tried #change to put an object to the array, but in that way the other el-select which bind the count of the data item cannot work.
<el-select
v-model="item.count"

Vuejs Filter add Span

I'm filtering with vuejs, only the output I want is written in the ".00" span in the comma. how can i do it?
html
1.500 ,00
component
<p class="amount">{{ 1500 | toTL }}</p>
filter
Vue.filter('toTL', function (value) {
return new Intl.NumberFormat('tr-TR', { currency: 'TRY', minimumFractionDigits: 2}).format(value);
});
output
1.500,00
I declared you value in the data() function like so :
data () {
return {
number: '1500,00',
newNumber: [],
}
},
What I did to make this work is make a created function like so :
created() {
this.newNumber = this.number.split(',')
},
Then, in the frontend (your p and span) :
<p>{{ newNumber[0] }}<span>,{{newNumber[1]}}</span></p>
What I did is turn a value into an array by using the split() function.
There is probably a way better solution but this is what I came up with in a short amount of time, I hope it helps.

VueJS2: How to pluck out one property of an array and use it to find matching value in the second array?

I have two arrays. I am trying to pluck out a property from one array and use it to find the value of another property in the other way. How to do this? Let me explain:
I have an array of objects that looks like so:
languageCodes:
{
"code1234char3": "mdr",
"name": "Mandar",
},
{
"code1234char3": "man",
"name": "Mandingo",
},
{
// etc...
},
I have another array of objects that looks like so:
divisionLanguages:
[
{
p_uID: 1,
nameLang3Char: 'mdr',
},
{
p_uID: 2,
nameLang3Char: 'man'
},
{
// etc..
}
]
I have a Vue template with an unordered list like so:
<ul v-for="x in divisionLanguages" :key="x.p_uID">
<li>Name: FOO
<li>Language: {{x.nameLang3Char}} - XXX</li> <--how to get 'name' value from 'languageCodes' and place here?
</ul>
Expected output should be:
Name: FOO
Language: mdr - Mandar
Name: BAR
Language: man - Mandingo
I tried to do something like in Vue SFC template (but did not work):
<li>Language: {{ languageName(x.nameLanguage3Char) }}</li>
...
methods: {
languageName(nameLanguage3Char) {
const name = this.divisionLanguages.filter(x => x.code6392char3 === nameLanguage3Char)
return name.name
}
I hope this makes sense of what I am trying to do.
Update: Thanks to #kellen in the comments, I change from filte() to find() like so:
languageName(nameLang3Char) {
const languageName = this.languageCodes.find(
x => x.code1234char3 == nameLang3Char
)
return languageName
},
and in I did:
<li>Language: {{ languageName(x.nameLang3Char).name }}</li>
and it works...but I get error in console:
Error in render: "TypeError: Cannot read property 'name' of undefined"
Have you tried combining these arrays before rendering them? If you were able to combine both objects before creating that list, that would make your life easier. Another thing I noticed is you're using filter, when find might be a better option to return a single value rather than an array. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find