I have an array
of objects:
ruta: [ { 'order': 1, 'id': 121 }, { 'order': 2, 'id': 123 } ]
I use it as a model for a buefy table and at the same time, I’m using the extension sortable.js to manually order the table rows:
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 //here for (let i = 0; i < data.length; i++) { data[i].order = i + 1; } } }) }
The table is rendered correctly, but I need to update the order
parameter on each manually sorting to reflect the real order o the table. For example, I need to move the fifth row to the beginning of the table, so its order
parameter should be 1 and the rest of the rows need to reflect 2, 3, 4 and 5.
As you can see in the code, I’ve tried:
for (let i = 0; i < data.length; i++) { data[i].order = i + 1; }
Because I want to start from 1 the value of the order. I also tried to put the change into the if / else
blocks:
if data[i].order = i + 1; else data[i].order = i - 1;
But it didn’t work either. The order of the rows is changed in a wrong way.
Advertisement
Answer
You already asked this on the Spanish SO site and I gave you a solution there. I know that you already solved the issue, but I’m going to post another solution to your question because it might be useful to other users in the future.
First of all, I already explained to you why this issue occurs: if you change the order of the model changing the values of its indexes, Vue
will not detect the change, you need to modify the array
in another way, for example, making an splice
. In your code, Vue
detects a change only when you change the order
parameter and at that moment the list is manually sorted, and the values of each index of the array
have changed, so, the view will be updated wrongly:
┌───────────────┬───────────────┬──────────────────┬───────────────┐ │ Initial state │ -> Model │ Manually sorting │ -> Model │ ├───────────────┼───────────────┼──────────────────┼───────────────┤ │ 1 - item 1 │ Array index 0 │ 1 - item 4 │ Array index 3 │ │ 2 - item 2 │ Array index 1 │ 2 - item 1 │ Array index 0 │ │ 3 - item 3 │ Array index 2 │ 3 - item 2 │ Array index 1 │ │ 4 - item 4 │ Array index 3 │ 4 - item 3 │ Array index 2 │ └───────────────┴───────────────┴──────────────────┴───────────────┘
The solution that I gave you before:
const createSortable = (el, options, vnode) => { // Copy the order property vnode.context.data.forEach( (obj) => {obj.norder = obj.order} ); // Create an array of orders const orders = vnode.context.data.map((obj) => obj.order); return Sortable.create(el, { ...options, onEnd: function (evt) { const data = vnode.context.data; // Update the position of the objects orders.splice(evt.newIndex, 0, ...orders.splice(evt.oldIndex, 1)); // Change the order parameter data.forEach((obj) => { obj.order = orders.findIndex((n) => n === obj.norder) + 1; }); } }); };
Working example: https://codepen.io/elchininet/pen/JLQqEV
Another solution:
Another solution is to reset the manually sorting after each movement and change the array
order using a splice
. Take a look:
const createSortable = (el, options, vnode) => { let order = []; return Sortable.create(el, { ...options, onStart: function (evt) { // when the sort starts, store the initial order of the array order = this.toArray(); }, onEnd: function (evt) { // when the sort ends, set the order to the initial state this.sort(order); // change the order using splice const data = vnode.context.data; data.splice(evt.newIndex, 0, ...data.splice(evt.oldIndex, 1)); // now it is safe, you can update the order parameter data.forEach((o, i) => { o.order = i + 1; }); } }); };
Here you have a working example: https://codepen.io/elchininet/pen/MVNaON