I have an array
of objects :
ruta :[
{ 'order': 1, 'id': 121 },
{ 'order': 2, 'id': 123 }
]
which I represent in a table using buefy . At the same time, I am using the sortable.js extension to vary the order of the table rows when dragging them:
const createSortable = (el, options, vnode) => {
return Sortable.create(el, {
...options,
onEnd: function (evt) {
const data = vnode.context.ruta
const item = data[evt.oldIndex]
if (evt.newIndex > evt.oldIndex) {
for (let i = evt.oldIndex; i < evt.newIndex; i++) {
data[i] = data[i + 1]
}
} else {
for (let i = evt.oldIndex; i > evt.newIndex; i--) {
data[i] = data[i - 1]
}
}
data[evt.newIndex] = item
//Aquí
for (let i = 0; i < data.length; i++) {
data[i].order = i + 1;
}
}
})
}
At the beginning the table is perfectly represented, but I need that when the position of the rows varies, the value of order
. For example, if the value of order
the last row is 5
and I drag it to the first row, this row should change its value of order
by 1
and the others should update their value depending on their position in the table.
I tried testing:
for (let i = 0; i < data.length; i++) {
data[i].order = i + 1;
}
Since I want the value of order
.
Also in the if
and else
above I tried with:
if
data[i].order = i + 1;
else
data[i].order = i - 1;
But it does not work.
This is the unordered table where the number is the value of the order
:
and when I try to raise Andrés García
what is in the position 4
to the position 1
this happens:
However, internally, they are sorted on the array
.
In this example, it should be Andrés García
first in line, but it puts it at the bottom and so it happens with the others.
What you're getting is due to the way Vue.js works : Every time the model is updated, the view is immediately updated taking the change in the model into account .
Each row of your list has as its model an object within the
array
data. In your code, each time you move a row, you vary the order of thearray
data elements by changing the contents of one index to another, which is not detected byVue
. For it toVue
detect the change you must vary thearray
, for example, applying asplice
. Therefore, with this operation the model is not changed and therefore the view is not updated. I will try to describe the process of your code by points:1 - When you move a
Andrés García
from position 4 to position 1, you have a loop that goes through thearray
data loop and placesAndrés García
first inside it, that is:2 - But
Vue
it has not detected this change, forVue
the view in row 4 (now first in the list) it still has index 3 of thearray
. Namely:3 - Then comes the code that you are trying to do that goes through each element of
array
and varies the parameterorder
, that is, you change the model of each row.4 - By varying the model of each row,
Vue
update the view:In my opinion, the logic of varying the order of the elements inside the
array
is superfluous, there is no need to update this order since it is being done directly in theDOM
consortable.js
. Look at the following starting code with no logic yet to update the number oforder
.:https://codepen.io/elchininet/pen/WzqVax
To update the property
order
of each row, a solution could be to have aarray
with the numbers oforder
and vary the position of these numbers within thearray
depending on the order given to the rows of the table. Then the parameterorder
of each row could be updated taking into account the position that each hasorder
within the mentionedarray
. Something like that:Here is a working example:
https://codepen.io/elchininet/pen/JLQqEV
EDIT: Another solution I have given you on SOen
This solution consists of saving the order of the items before starting to drag a row and once the row has been moved, restore the order to the initial state and only then apply an
splice
alarray
toVue
update the view:Working example: https://codepen.io/elchininet/pen/MVNaON