Reputation: 2412
I'm writing a small app that uses the react-sortable-hoc
everything is great but im having issues displaying the list ordered by order
I have
user 0
user 1
user 2
when I drag user 2 above user 0 instead of getting
user 2
user 0
user 1
I get
user 2
user 1
user 0
I think It has to do with the way I'm setting the order in the state. but I can't figure it out.
this is how I set the order on sort end
const onSortEnd = ({ oldIndex, newIndex }) => {
setUsers(prevState => {
const newItems = [...prevState];
newItems[newIndex].order = oldIndex;
newItems[oldIndex].order = newIndex;
return newItems.sort((a, b) => a.order - b.order);
})
};
here's the app running so you can play with it. https://codesandbox.io/s/winter-https-xelrd?fontsize=14&hidenavigation=1&theme=dark
Upvotes: 1
Views: 2689
Reputation: 195992
What you do is swapping.
If you want to just "insert" the element in the new position you will have to update all the items between the two positions.
In your case, one approach would be to just move the element and re-create the order for all items
setUsers(prevState => {
const newItems = [...prevState];
newItems.splice(newIndex, 0, newItems.splice(oldIndex, 1)[0]).forEach((item,index)=>{
item.order = index;
});
return newItems
});
Demo at https://codesandbox.io/s/confident-river-mrh3p
Upvotes: 1
Reputation: 6255
So looks like your code is simply swapping the elements. This does not seem like what you really want to do. In fact you really want to remove the element and insert it at a given position. I think since you already have the oldIndex and newIndex, you can approach the sort function as follows:
const onSortEnd = ({ oldIndex, newIndex }) => {
setUsers(prevState => {
var newItems = [...prevState];
let elem = newItems[oldIndex]
newItems.splice(oldIndex, 1)
newItems.splice(newIndex, 0, elem)
return newItems
});
};
There isn't really a need for order and is capturing more than the minimum state required (unless you use it elsewhere).
Upvotes: 0
Reputation: 3411
I have fixed it, here is the working url to play with https://codesandbox.io/s/quizzical-colden-rm62y
You were correct in guessing that the problem was with the onSortEnd
function. Instead of swapping the newIndex and oldIndex position we just need to either bubble them up or down.
Here is a working code, it can be cleaned up a bit, but you got the idea :)
const onSortEnd = ({ oldIndex, newIndex }) => {
setUsers(prevState => {
const newItems = [...prevState];
if (oldIndex > newIndex) {
for (let i = oldIndex - 1; i >= newIndex; i--) {
newItems[i].order++;
newItems[oldIndex].order = newIndex;
}
} else if (oldIndex < newIndex) {
for (let i = oldIndex + 1; i <= newIndex; i++) {
newItems[i].order--;
newItems[oldIndex].order = newIndex;
}
}
return newItems.sort((a, b) => a.order - b.order);
});
};
Hope it helps. Happy coding :)
Upvotes: 1