array.slice strange behaviour with nuxt-edge - javascript

EDIT AND SOLVED:
I've found the origin of the problem:
I thought arr.slice returned the new array but, actually, it returns the deleted element. See the documentation
The solution is simply to put the slice function before the bracket and not in it:
remove (index) {
const arrayCopy = this.liens.slice()
arrayCopy.splice(index, 1)
this.$emit('update:liens', arrayCopy)
}
Thank you kissu for your time!
I was previously using nuxt 2.xx and since switching to nuxt-edge the vue behavior changed with array.slice. Let me explain :
My code is very basic and is used to add/remove items of an array in a child component "stockLiens". This array is passed to a parent component "currentEtabCommentUser" via .sync
Everything was working fine before but since I'm with nuxt-edge, if I have - for instance - an array of 3 items and I want to delete the 2nd one, it is the only item left!
My stockLiens component Javascript is the following:
props: {
liens: {
type: Array,
default: () => []
}
},
methods: {
// I used concat() and slice() to avoid mutating a prop in the component
add () {
const arrayConcat = this.liens.concat([{ url: '', description: '' }])
this.$emit('update:liens', arrayConcat)
},
remove (index) {
const arrayCopy = this.liens.slice()
console.log(this.liens) // line 108
console.log(arrayCopy) // line 109
this.$emit('update:liens', arrayCopy.splice(index, 1))
console.log(arrayCopy) // line 111
}
}
When I run the script, the text in the firefox console is the following:
On the picture, you can see that :
stockLiens:108 is an array of 3 items (it makes sense since it is this.liens)
stockLiens:109 is an array of 2 items! (strange since it's a simple array.slice() of this.liens) The 2 items are the old index 0 and the old index 2 (I've clicked on old index 1)
stockLiens:111 is the same array that on line 109. (strange again because it should have been spliced in line 110)
currentEtabCommentUser:186 is an array of 1 item : the old index 1 (since line 186 is just a listener on this.liens, it should be the same array that on stockLiens:111. I really don't understand anything!)
My currentEtabCommentUsercomponent:
<stockLiens
:liens.sync="liens"
/>
<script>
watch: {
liens () {
console.log(this.liens) // line 186
}
}
</script>
I've tried to change .sync, to copy the array with for(i...), to get() / set(v) the liens property, ... I've looked on many forum during hours (2 days now) but I can't understand the problem.
Can someone help me please ?
Thank you in advance!
My stockLiens component HTML:
<v-card
v-for="(url, i) in liens"
:key="i"
>
<v-text-field
v-model="url.url"
label="Url"
/>
<v-text-field
v-model="url.description"
label="Description"
/>
<v-divider vertical />
<v-btn
icon
#click="remove(i)"
>
<v-icon>mdi-delete-forever-outline</v-icon>
</v-btn>
</v-card>

Related

Can't get mutator logic to correctly add the proper amount of items into a cart

I'm trying to make an add to cart function that first checks if the item being added is already in the cart. If it's in the cart, update its quantity property. If not in the cart, add the entire object to the cart. I think my problem is I'm getting the logic wrong inside my "ADD_ITEM_TO_CART" mutator function.
This is my store with some console.logs() from when I click "addToCart()"
state: {
checkoutCart: [],
},
actions: {
cartAdd({ commit }, payload) {
commit("ADD_ITEM_TO_CART", payload);
},
},
mutations: {
ADD_ITEM_TO_CART(state, payload) {
//CONSOLE.LOG()'s
console.log("state.checkoutCart[0]", state.checkoutCart[0]);
// eslint-disable-next-line
console.log("state.checkoutCart[0].item", state.checkoutCart.item);
console.log("state.checkoutCart", state.checkoutCart);
//IF ITEM ALREADY IN checkoutCart, UPDATE IT'S QUANTITY
if (state.checkoutCart.includes(payload.item)) {
state.checkoutCart.quantity += payload.quantity;
console.log("Item already in cart");
}
//IF ITEM NOT IN checkoutCart, UPDATE THE QUANTITY PROPERTY AND ADD ITEM TO CART
else {
payload.item.quantity = payload.quantity;
state.checkoutCart.push(payload);
}
https://i.imgur.com/rjOOljN.png
I thought this code would work, but it ALWAYS executes the ELSE condition and adds to cart like the
if (state.checkoutCart.includes(payload.item))
isn't being recognized or working at all.
https://i.imgur.com/LLB790Z.png
VueX devtools shows the same thing. An "item" object inside an object inside an array.
I also tried:
ADD_ITEM_TO_CART(state, payload) {
console.log("add_item_to_cart"); <---ONLY PART THAT SHOWS UP IN CONSOLE.LOG() WHEN EXECUTED
//LOOP THROUGH ALL ARRAY ENTRIES TO GAIN ACCESS TO state.checkoutCart.item
for (let i = 0; i < state.checkoutCart.length; i++) {
console.log("i=", i);
console.log("state.checkoutCart.item", state.checkoutCart.item);
//IF ITEM ALREADY IN checkoutCart, UPDATE IT'S QUANTITY
if (state.checkoutCart[i].item.includes(payload.item)) {
state.checkoutCart.quantity += payload.quantity;
console.log("Item already in cart");
return;
};
}
//IF ITEM NOT IN checkoutCart, UPDATE THE QUANTITY PROPERTY AND ADD ITEM TO CART
payload.item.quantity = payload.quantity;
state.checkoutCart.push(payload);
},
because I figured I needed to loop through all the array entries. BUT the for loop doesn't even run, and with this code nothing gets added to the cart at all.
I can't figure out what I'm doing wrong here. Can somebody help? Is my syntax wrong? Or is my logic? Am I accessing the arrays/objects incorrectly? How do I write the "ADD_ITEM_TO_CART" mutator function correctly? I've literally spent all day on this and my brain is shutting down.
EDIT:
https://i.imgur.com/bkU8YSo.png
PAYLOAD
<div v-for="item in items"> <--ACTUALLY PROP FROM PARENT COMPONENT BUT SAME IDEA
<p>
Qty
<select v-model="quantity">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</p>
<p>
<button type="button" #click="addToCart()">
Add to Cart
</button>
</p>
</div>
let quantity = ref("1");
const addToCart = () => {
console.log("addToCart Running");
store.dispatch("cartAdd", { item: item.value, quantity: quantity.value });
};
That is because your if condition is not checking for what you think.
Array.prototype.includes checks if a value is in the array but there are two cases:
the value is a primary type (string, number, boolean, ...). It compares by value.
the value is an object. Then it compares by reference.
So here, you are checking if the reference of your item object is already included in the array. But it's not, since it's a new object.
Solution: check if there is an object with the same values, not reference.
You can use the some method, and you have to write a condition that checks if two items are equals.
Here is an example if your items have an id:
if (state.checkoutCart.some(item => item.id === payload.item.id))
The problem is indeed inside ADD_ITEM_TO_CART mutation.
As Kapcash has pointed out, two objects having the same properties and the same values are not the same.
In other words, .includes() checks for identity, not equality. To better understand this, consider this example:
const a = { foo: 'bar' }
const b = [{ foo: 'bar' }]
const c = [a]
const d = [{ ...a }]
console.log(b.includes(a)) // false
console.log(c.includes(a)) // true
console.log(d.includes(a)) // false
To get past this, use Kapcash's answer.
I'll just mention the standard way of dealing with this problem is using unique identifiers on objects (e.g: uuids).
Once you fix the above, it's still not going to work, because you'll run into the following problem: inside the if you're attempting to alter state.checkoutCart's quantity. And an array does not have a quantity property.
The proper logic to achieve the desired functionality is (assuming the unique identifier on checkoutCart members is item._id, from the pictures you posted):
ADD_ITEM_TO_CART(state, payload) {
// find the index of a cart element having same `item._id` value as the payload
const index = state.checkoutCart.findIndex(
(el) => el.item._id === payload.item._id
)
if (index > -1) {
// if the index is higher than `-1`, an element was found
// create a copy, update its quantity and then
// replace the original element with the copy
const copy = { ...state.checkoutChart[index] }
copy.quantity += payload.quantity
state.checkoutCart.splice(index, 1, copy)
} else {
// no element found, add payload to `checkoutCart`
state.checkoutCart.push(payload)
}
}
Side note: None of your items should contain a quantity property. That's the cart's responsibility, not the item's. By adding it to the item you end up with two sources of truth which you'd need to keep in sync. You don't want this type of problem.

React-table with select and dropdown

Edit Note:Link with working version at bottom of post
I have run into some really weird behavior with my project
I have the parent which gets some data from a database and passes it to the child (which is a popup). The child then uses useEffect to detect when the data is ready (black part) and sets the value in the child (blue part).
useEffect(() => {
console.log(datachannels.length)
if (datachannels.length > 1) {
let newValueState = []
let c = 0
datachannels.forEach(element => {
newValueState.push({ id: c, dc: element.dataChannel, axis: "y" })
c += 1
});
setValueState(newValueState)
console.log(newValueState)
console.log("trigger")
}
}, [datachannels])
Then when a user changes a option this code runs to update it(Green part)
const handler = (event, id) => {
console.log(valueState)
const value = event.value
console.log(valueState.length)
if (valueState.length > 0) {
let newValueState = valueState
newValueState.forEach(key => {
if (key.id == id) {
console.log(key)
key.axis = value
}
});
setValueState(newValueState)
}
}
With inspect i can see that the value is not empty but the handler function trying to use it is telling me its empty. When giving valueState a default value and after useEffect code runs, I try and access it but it just returns the default value. I have no idea what is causeing this or what to google so if anyone can shead some light on this, I would be very happy
Update 1: Codesandebox (new link below) I have not been able to get the bug to show yet
Update 2:Code in sandbox now has error. As you can see when useEffect runs the object has 3 values but when the user changes the dropdown it only has one value
Update 3: To see the bug in the sandbox change one of the axis drop downs
Update 4: Porok12 answer works in the sand box but is not working in my actully project and i have no idea what is going on
Update 5: So when using Porok12 code and feeding in datachannels the same way as the sandbox it does work but with some other weird behavior that im hopping can point to the problem. When changing a dropdown this is outputted to the console. From input was changed to (3) [{},{},{}] is the correct behavior but then everything rerenders as seen from the other messages. I have no idea why it is behaving differently from porok12 code as it is the same. But this does point out a problem with how datachannels is being passed in? In the parent object I am storing the channels like this
if (data !== undefined) {
let parseData = JSON.parse(data);
let toPush = []
Object.keys(parseData).forEach(key => {
toPush.push({ "dataChannel": key })
});
setDataChannels(toPush);
And feeding it to the child like this <BuilderTable handleupdate={handleUpdate} datachannels={dataChannels} show={modalShow} onHide={() => setModalShow(false)} />
Update 6: So its now working with Porok12 code after i changed the useMemo [] to use valueState instead of datachannel. The only problem now is that the dropdown reset to the starting value every time you change it
Update 7: With the change from update 6 and feeding valueStatus into the dropdowns the problem is not fixed.
Update 8: https://codesandbox.io/s/spring-water-2ucq8u?file=/src/GraphBuilderFull.js Here is the sandbox link with a working version
Side note: you can change
let c = 0
datachannels.forEach(element => {
newValueState.push({ id: c, dc: element.dataChannel, axis: "y" })
c += 1
});
to
const newValueState = datachannels.map((element, index) => ({id: index, dc: element.dataChannel, axis: "y"}))
The problem is that you use useMemo that way:
const selectChannelTableColumn = React.useMemo(
() => [
{
Header: "Axis Selection",
Cell: ({ row }) => (
<div>
<Dropdown
id={row.id}
options={axis}
onChange={(e) => handler(e, row.id)}
placeholder="y"
/>
</div>
)
}
],
[] // missing `datachannels` xor `valueState` dependency
);
If you will add datachannels to dependencies it will work. You should also move handler definition to this useMemo code.
Here is fixed sandbox example
The changes I made:
Move handler definition to selectChannelTableColumn code
Fix handler logic
Move selectChannelTableColumn under (meaning below not inside) your useEffect
Add datachannels to useMemo hook dependencies

How made a deep copy that can resolve a problem with a table

Im using the table material-table, where the set a new element to my object, called tableData. So that feature create an issues to my code and API because I update using Patch. I implemented a conventional and also custom deep copy of my object to avoid the table add this element to my object.
But for some reason it isnt working. This is an example of the table where you can see how it added the tableData to the example object. https://codesandbox.io/s/lx2v9pn91m Please check the console
Above I showed the real object, and in the element 5 array, appear the tableData after each render. Extra comment, the property of the table I passed to table is: data={MyRealObject.element5}
This is the struct of my real object:
MyRealObject{
element1: boolean,
element2: boolean ,
element3: Array ,
element4: Array ,
Cards: Array ,
}
Card{
Id: number ,
CardNumber : number ,
CardFormat : {CardFormatObject},
//here where appear the tableData after each render
}
CardFormatObject{
Id: number ,
CardNumberLength : number ,
CardFormatLength : number ,
Default:boolean ,
Name: string ,
}
This is the lastest custom deep copy I did and didnt work:
deepcopy(MyRealObject:MyRealObject):MyRealObject{
let salvaCard=[]
for(let i=0;i<user.Cards.length;i++){
salvaCard[i]=this.deepCardCopy(MyRealObject.Cards[i])
}
return{
element1: MyRealObject.element1,
element2: MyRealObject.element2,
element3: [...MyRealObject.element3], //I know here is not deep but isnt important now, and it isnt affected
element4: [...MyRealObject.element4],
Cards: salvaCard,
}as MyRealObject
}
public deepCardCopy(card:Card):Card{
return {
Id:card.Id,
CardNumber:card.CardNumber,
CardFormat:{...card.CardFormat}
} as Card;
}
//////////////////////////////
This are others deep code that I used and dont works, I share to save you time:
--------old solution 1(i dont like it, you can lose element if there are null)------------------------------------------------
// Cards: JSON.parse(JSON.stringify(MyRealObject.Cards)),
---------old solution 2-------------------------------------------
// MyRealObject.Cards.map(card=>{
// const {tableData,...record}=card
// return record
// }),
setState is an async function. That means you won't see the result right after calling it. You have to wait for setState to be finished. There is a callback-Parameter in setState which you can use to get the result of this.state
handleSelectedID = rowData => {
const selectedID = rowData.map(item => item.id);
this.setState({ selectedID }, () => {
// setState is async
// this is the callback
console.log(this.state.selectedID);
});
};
I changed your example-code a bit to give you an example of it: https://codesandbox.io/s/1olz33pmlj
I found a solutions, it is passsing the clone in the moment i passed the object to the table, for example:
data={MyRealObject.map(x => Object.assign({}, x))}
The issues was, that the people that create the table didnt make a clone to the data, the use the same reference, so it will be better do this to avoid problems that some one in the component didnt clone the object.
Kindly, noted, DONT used this way
data={...MyRealObject} or data={Object.assign({}, MyRealObject)}
The CORRECT is:
data={MyRealObject.map(x => Object.assign({}, x))}
Both expression look similiar but it isnot the same.

v-model not update after settimeout finish Vue [duplicate]

I'm new to Vuejs. Made something, but I don't know it's the simple / right way.
what I want
I want some dates in an array and update them on a event. First I tried Vue.set, but it dind't work out. Now after changing my array item:
this.items[index] = val;
this.items.push();
I push() nothing to the array and it will update.. But sometimes the last item will be hidden, somehow... I think this solution is a bit hacky, how can I make it stable?
Simple code is here:
new Vue({
el: '#app',
data: {
f: 'DD-MM-YYYY',
items: [
"10-03-2017",
"12-03-2017"
]
},
methods: {
cha: function(index, item, what, count) {
console.log(item + " index > " + index);
val = moment(this.items[index], this.f).add(count, what).format(this.f);
this.items[index] = val;
this.items.push();
console.log("arr length: " + this.items.length);
}
}
})
ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<div id="app">
<ul>
<li v-for="(index, item) in items">
<br><br>
<button v-on:click="cha(index, item, 'day', -1)">
- day</button>
{{ item }}
<button v-on:click="cha(index, item, 'day', 1)">
+ day</button>
<br><br>
</li>
</ul>
</div>
EDIT 2
For all object changes that need reactivity use Vue.set(object, prop, value)
For array mutations, you can look at the currently supported list here
EDIT 1
For vuex you will want to do Vue.set(state.object, key, value)
Original
So just for others who come to this question. It appears at some point in Vue 2.* they removed this.items.$set(index, val) in favor of this.$set(this.items, index, val).
Splice is still available and here is a link to array mutation methods available in vue link.
VueJS can't pickup your changes to the state if you manipulate arrays like this.
As explained in Common Beginner Gotchas, you should use array methods like push, splice or whatever and never modify the indexes like this a[2] = 2 nor the .length property of an array.
new Vue({
el: '#app',
data: {
f: 'DD-MM-YYYY',
items: [
"10-03-2017",
"12-03-2017"
]
},
methods: {
cha: function(index, item, what, count) {
console.log(item + " index > " + index);
val = moment(this.items[index], this.f).add(count, what).format(this.f);
this.items.$set(index, val)
console.log("arr length: " + this.items.length);
}
}
})
ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.11/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<div id="app">
<ul>
<li v-for="(index, item) in items">
<br><br>
<button v-on:click="cha(index, item, 'day', -1)">
- day</button> {{ item }}
<button v-on:click="cha(index, item, 'day', 1)">
+ day</button>
<br><br>
</li>
</ul>
</div>
As stated before - VueJS simply can't track those operations(array elements assignment).
All operations that are tracked by VueJS with array are here.
But I'll copy them once again:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
During development, you face a problem - how to live with that :).
push(), pop(), shift(), unshift(), sort() and reverse() are pretty plain and help you in some cases but the main focus lies within the splice(), which allows you effectively modify the array that would be tracked by VueJs.
So I can share some of the approaches, that are used the most working with arrays.
You need to replace Item in Array:
// note - findIndex might be replaced with some(), filter(), forEach()
// or any other function/approach if you need
// additional browser support, or you might use a polyfill
const index = this.values.findIndex(item => {
return (replacementItem.id === item.id)
})
this.values.splice(index, 1, replacementItem)
Note: if you just need to modify an item field - you can do it just by:
this.values[index].itemField = newItemFieldValue
And this would be tracked by VueJS as the item(Object) fields would be tracked.
You need to empty the array:
this.values.splice(0, this.values.length)
Actually you can do much more with this function splice() - w3schools link
You can add multiple records, delete multiple records, etc.
Vue.set() and Vue.delete()
Vue.set() and Vue.delete() might be used for adding field to your UI version of data. For example, you need some additional calculated data or flags within your objects. You can do this for your objects, or list of objects(in the loop):
Vue.set(plan, 'editEnabled', true) //(or this.$set)
And send edited data back to the back-end in the same format doing this before the Axios call:
Vue.delete(plan, 'editEnabled') //(or this.$delete)
One alternative - and more lightweight approach to your problem - might be, just editing the array temporarily and then assigning the whole array back to your variable. Because as Vue does not watch individual items it will watch the whole variable being updated.
So you this should work as well:
var tempArray[];
tempArray = this.items;
tempArray[targetPosition] = value;
this.items = tempArray;
This then should also update your DOM.
Observe object and array reactivity here:
https://v2.vuejs.org/v2/guide/reactivity.html

How do I reverse the order of an array using v-for and orderBy filter in Vue JS?

I am using Vue JS to do viewmodel bindings. In my data object I have an array of items that are sorted in ascending order (oldest to newest) and I'd like to keep it that way for code-based reasons.
var v = new Vue({
el: '#app',
data: {
items: [
{id: 51, message: 'first'},
{id: 265, message: 'second'},
{id: 32, message: 'third'}
],
}
}
However, when I display the array in the template I'd like to reverse the order so that it's descending (newest to oldest). I tried the following:
<ol>
<li v-for="item in items | orderBy -1" track-by="id">
This didn't work since the orderBy filter seems to require a field name as its first argument.
Is there any way to accomplish this in the template using the v-for syntax using the orderBy filter? Or am I going to have to create a custom reverse filter?
Simple and concise solution:
<li v-for="item in items.slice().reverse()">
//do something with item ...
</li>
Instead of reversing the order of the elements for creation, I only change the order of the display.
<ol class="reverseorder">
<li v-for="item in items" track-by="id">
And my CSS
<style>
.reverseorder {
display: flex;
flex-direction: column-reverse;
}
</style>
No need to clone the array and reverse it.
Note: The below works in Vue 1, but in Vue 2 filters are deprecated and you
will see: ' Property or method "reverse" is not defined on the
instance but referenced during render.' See tdom_93's answer for
vue2.
You could create a custom filter to return the items in reversed order:
Vue.filter('reverse', function(value) {
// slice to make a copy of array, then reverse the copy
return value.slice().reverse();
});
Then use it in the v-for expression:
<ol>
<li v-for="item in items | reverse" track-by="id">
https://jsfiddle.net/pespantelis/sgsdm6qc/
Update for Vue2
I want to show some ways that you can work with data and not using filters as they are deprecated in Vue2:
inside computed property
Use computed properties in place of filters, which is much better because you can use that data everywhere in component, not only just in template:
jsFiddle
computed: {
reverseItems() {
return this.items.slice().reverse();
}
}
inside Vuex getter property
If you're using Vuex, and you store your data in store.state object. The best way do some transformation with data stored in state is to do that in getters object (for example filtering through a list of items and counting them, reverse order and so on...)
getters: {
reverseItems: state => {
return state.items.slice().reverse();
}
}
and retrieve state from getters in component computed property:
computed: {
showDialogCancelMatch() {
return this.$store.state.reverseItems;
}
}
Possibly I'm missing some downsides here, but how about iterating over the array from end to start using an index?
<ol>
<li v-for="i in items.length" :set="item = items[items.length - i]">
Like, if your array consists of thousands of elements, copying it with .slice().reverse() every time is probably not the most efficient approach.
Upd.: note, :set is not an official way for defining variables in template, it just works. As an alternative, the item variable could be replaced by a call to some getItem(i) method that would encapsulate the items[items.length - i] expression.
Based on the fact that the directive v-for can accept not only an array but also any other valid JavaScript iterable object (at least in Vue 2.6+ and Vue 3 releases), we can create our own iterable object to loop through a needed array in the opposite direction. I created a very simplified runnable example (for more details - check information about the JavaScript iterator protocol).
class Iterable {
constructor(arr) {
this.arr = arr;
}
*[Symbol.iterator]() {
const arr = this.arr;
for (let i = arr.length - 1; i >= 0; i--) yield arr[i];
}
getIterable(isReversedOrder) {
return isReversedOrder ? this : this.arr;
}
}
Vue.component('list', {
props: ['iterable'],
template: '<ul><li v-for="(el, i) in iterable" :key="`${i}-${el}`">{{ el }}</li></ul>'
});
const app = new Vue({
data() {
return {
todos: new Iterable(['Learn JavaScript', 'Learn Vue', 'Learn Vuex']),
isReversed: true,
inputValue: ''
};
},
computed: {
computedTodos() {
return this.todos.getIterable(this.isReversed);
}
},
methods: {
toggleReverse() {
this.isReversed = !this.isReversed;
},
addTodo() {
this.inputValue && this.todos.arr.push(this.inputValue);
this.inputValue = '';
}
}
});
app.$mount('#app');
<!DOCTYPE html>
<html>
<body style="display: flex; justify-content: center;">
<div id="app">
<button #click="toggleReverse">Toggle reverse to {{ !isReversed }}</button>
<br />
<input v-model="inputValue" style="margin-top:5px;" />
<button #click="addTodo" :disabled="!inputValue">Add todo</button>
<!-- <ul><li v-for="(todo, i) in computedTodos" :key="`${i}-${todo}`">{{ todo }}</li></ul> -->
<list :iterable="computedTodos" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<script src="script.js"></script>
</body>
</html>
P.S.Try to avoid using such Array.prototype functions as shift/ unshift , reverse etc. to add / remove items from the beginning of the array or reverse the order, especially in the case when such operations are performed frequently and / or an array includes a big quantity of items, because they are quite costly as for performance (have O(n) complexity).
Another good solution is to use CSS to display elements in the reversed order (see an answer above).
The v-for directive doesn't support iterating backwards, so if you want to order by newest you're going to need to add another field to indicate when the item was added, or change id to increment every time an item is added.
Then, with field being the field indicting the order added:
<li v-for="item in items | orderBy 'field' -1" track-by="id">
For my use case (which is admittedly, apparently different than the OP...) I wanted to have the indices of the Array in reverse order in the v-for "loop."
My solution was to create a Vue app method reverseRange(length) that returns an Array of integers from length-1 to 0. I then used that in my v-for directive and simply referred to my Array elements as myArray[index] every time I needed it.
That way, the indices were in reverse order and I was able to then use them to access elements of the Array.
I hope this helps someone who landed on this page with this subtle nuance in their requirements like me.
You can use lodash reverse:
<li v-for="item in _.reverse(items)">

Categories

Resources