Vue 3: Rendering the object in descending order issue - vue.js

I am trying to render the data in the desc order, but vue 3 always render it in the asc order
state: {
entries: {
2022: {
10: {...},
11: {...},
12: {...},
...
},
2021: {
10: {...},
12: {...},
...
},
2020: {
3: {...},
8: {...},
...
},
},
}
But it always renders like this 2020, 2021, 2022 where as I require it to be 2022, 2021, 2020,
How to fix it

integers are iterated first in the ascending order
Small Demo demonstrating above statement.
var jsonObj = {
3: 'March',
1: 'Jan',
5: 'May'
};
console.log(jsonObj);
That's what a JavaScript engine recognizes as an integer and what humans recognize as a number are not same.
To achieve the order, we can convert that object into an array.
Demo :
const app = new Vue({
el: '#app',
data() {
return {
list: [{
3: 'March' }, {
1: 'Jan' }, {
5: 'May' }]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<body>
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="index">
{{ item[Object.keys(item)[0]] }}
</li>
</ul>
</div>
</body>

Related

Hide vue paginate button if element doesn't exist

I'm trying to hide a vue paginate button if the item doesn't exist in my array. My code:
<b-pagination
:key="currentQuestionPage"
v-model="currentQuestionPage"
:total-rows="submissionFiles.length"
:per-page="perPage"
align="center"
first-number
last-number
limit="20"
#input="changePage()"
>
<template v-slot:page="{ page, active }">
{{ submissionFiles[page - 1][currentStudentPage - 1] && submissionFiles[page - 1][currentStudentPage - 1].order }}
</template>
</b-pagination>
However, instead of the button not rendering (what I'm hoping for), I'm getting a "blank" button:
Is there any way to prevent the button from rendering at all if it has empty content?
I don't think you show enough code to get a particularly useful answer here, but my guess would be:
You need to first create a computed property which is an array only of the items you want.
That way you end up with something more like this:
new Vue({
el: '#app',
data() {
return {
perPage: 3,
currentPage: 1,
items: [
{ id: 1, test: true },
{ id: 2, test: false },
{ id: 3, test: true },
{ id: 4, test: false },
{ id: 5, test: true },
{ id: 6, test: true },
{ id: 7, test: false },
{ id: 8, test: true },
{ id: 9, test: false },
]
}
},
computed: {
// Here we compute the actual items we want:
usedItems(){
return this.items.filter(i => i.test);
},
rows() {
// Now we remove the previous "rows" var and use the computed property instead
// return this.items.length
return this.usedItems.length
}
}
})
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<div class="overflow-auto">
<b-pagination
v-model="currentPage"
:total-rows="rows"
:per-page="perPage"
aria-controls="my-table"
></b-pagination>
<p class="mt-3">Current Page: {{ currentPage }}</p>
<b-table
id="my-table"
<!-- Update items to show only the filtered selection: -->
:items="usedItems"
:per-page="perPage"
:current-page="currentPage"
small
></b-table>
</div>
</div>

Vuejs - How to get all unique values in a array (remove duplicates) using v-for

How to show only one button per every distinct date ?
can i use two v-for loops ? how to select distinct values in my loop?
<div v-for="question in allQuestions" >
<button v-for="date in question.date">
{{date}}
</button>
</div>
Data model :
allQuestions : []
question : {'id' : '123' , 'date' : '25'}
You can use Set:
The Set object lets you store unique values of any type, whether primitive values or object references.
MDN's example:
const numbers = [2, 3, 4, 4, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 5, 32, 3, 4, 5]
console.log([...new Set(numbers)])
Just modify it to your needs.
Use reduce to execute a reducer function on each item of the array, then merge the individual matches into the existing object with assign. This merging process takes care of removing (or actually replacing) duplicate items.
const vm = new Vue({
el: '#app',
data() {
return {
allQuestions: [
{ id: '123', date: '14' },
{ id: '456', date: '2' },
{ id: '933', date: '2' },
{ id: '789', date: '7' },
{ id: '220', date: '14' }
]}
},
computed: {
uniqueQuestions() {
return this.allQuestions.reduce((seed, current) => {
return Object.assign(seed, {
[current.date]: current
});
}, {});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="question in uniqueQuestions" :key="question.date">
<button v-for="date in question.date">
{{date}}
</button>
</div>
</div>
You can use computed to display an array of all your questions sorted by date.

v-for in VueJS, how to keep track of previous components data?

I would like to output a series of entries, which contains a value.
But for each line, I would like to display the sum of all values from start to the current line.
For example:
// App.vue
<template>
<div>
<Row v-for="item in items" :value="item.value"/>
</div>
</template>
<script>
export default {
data() {
items: [{ value: 3}, {value: 5}, {value: 1}, {value: 9}, {value: 3}]
}
}
</script>
// Row.vue
<template>
<div>{{ value }} (Sum: <subtotal here>)</div>
</template>
<script>
export default {
props: ['value']
}
</script>
I would like this output :
<div>
<div>3 (Sum: 3)</div>
<div>5 (Sum: 8)</div>
<div>1 (Sum: 9)</div>
<div>9 (Sum: 18)</div>
<div>3 (Sum: 21)</div>
</div>
I already tried multiple way, emitting an event on Row creating/updating, using a local variable in App...
Using a local non-reactive variable causes bad behavior when updating a component. And using prop ou event cause an infinite loop.
How could I sum progressively each item value?
Use a computed property to keep the count for you:
new Vue({
el: '#app',
template: '#template',
data: {
items: [{ value: 3}, {value: 5}, {value: 1}, {value: 9}, {value: 3}]
},
computed: {
calculatedItems() {
const newArray = [];
let sum = 0;
for(let i = 0; i < this.items.length; i++) {
sum += this.items[i].value;
newArray.push({
total: sum,
item: this.items[i],
});
}
return newArray;
},
},
})
<!-- development version, includes helpful console warnings -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app"></div>
<template id="template">
<div>
<div v-for="item in calculatedItems">
{{ item.item.value }},
Total: {{ item.total }}
</div>
</template>
This basically makes a copy of your list, and calculates the total values for every entry, this is also more performing that looping for every item to count the values, as this only loops 1 time, and the value is cached

How to display object key value?

I need to display key value from object. Here is my code:
new Vue({
el: '#app',
data: {
x: {"2018-05-11":{"may":4,"june":8,"april":5}}
}
})
In my template I would like to display: 2018-05-11, but not {"2018-05-11":{"may":4,"june":8,"april":5}}. How I can do it?
https://jsfiddle.net/grnok86b/
You can use computed and Object.keys for return key as value.
for example:
new Vue({
el: '#app',
data: {
x: {
"2018-05-11": {
"may": 4,
"june": 8,
"april": 5
}
}
},
computed: {
date() {
return Object.keys(this.x)[0];
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<p>My date is {{date}}</p>
</div>
you can loop it if you want
You can always create a computed method:
new Vue({
el: '#app',
data: {
x: {
"2018-05-11": {
"may": 4,
"june": 8,
"april": 5
}
}
},
computed: {
foo() {
return Object.keys(this.x)[0]
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<p>{{ foo }}</p>
</div>
I have created a function even to do this procedure.
HTML
<p v-for="entidade in relato.entidade">${acessaEntidade(entidade)}</p>
The function in methods
JS
acessaEntidade: function (id) {
return this.entidades['nome' + id]
},
In the case I have a variable that is loaded and that variable there are indexes, 1, 2, 3 ... I get these indexes and consult in a new function to return the value by querying on another variable. If you need help, tell me by email :)

Vue slot-scope with v-for, data changed but not re-rendered

I have a question while I'm studying vuejs2
I made an example with slot-scope && v-for, but it has an error which I can't understand.
Here is example code
https://jsfiddle.net/eywraw8t/6839/
app.vue
<template id="list-template">
<div>
<ul>
<slot name="row" v-for="item in list" v-bind=item />
</ul>
</div>
</template>
<div id="app">
<list-component :list="list">
<li slot="row" slot-scope="item">
{{item.name}}
</li>
</list-component>
</div>
Vue.component('list-component', {
template: '#list-template',
props: {
list: {
type: Array
}
}
});
new Vue({
el: '#app',
data () {
return {
list: [
{id: 1, name: 'Apple'},
{id: 2, name: 'Banana'},
{id: 3, name: 'Cherry'},
{id: 4, name: 'Durian'},
{id: 5, name: 'Eggplant'}
]
}
},
methods: {
h (item) {
item.name = item.name.toUpperCase()
console.log('Changed!')
console.log(item)
}
}
});
Strange thing is, the method 'h' is triggered and then, the console said 'Changed!' and data also changed but, the view is not re-rendered.
What am I missing? I think slot-scoped object data is not referencing the original object data.
What should I do to modify the original data?
Thanks for reading this question.
You are directly trying to modify the value of an item in an array. Due to some limitations vue cannot detect such array modifications.
So update your code to use vm.$set() to make chamges to the array item.
methods: {
h (item) {
let i = this.items.findIndex((it) => it.id === item.id);
this.$set(this.list, i, {...item, name: item.name.toUpperCase()});
console.log(item.id)
}
Here is the updated fiddle