sagalbot / vue-sortable

A lightweight directive for reorderable drag-and-drop lists using RubaXa/Sortable
http://sagalbot.github.io/vue-sortable/
MIT License
721 stars 104 forks source link

Bug when replacing last item in v-for [vue 1.0.13] #27

Open Leotomas opened 7 years ago

Leotomas commented 7 years ago

Hi, We're using vue 1.0.13 and ended up using your library, thanks for your work.

We've encountered an issue when dragging an item in a v-for from any position into the last position of the list. It seems that the last item is placed after the "v-for end" comment in the DOM. It does not affect the behaviour of further dragging and dropping items in the list, however when we try to push something in the list, the console throws an exception.

Here's a screenshot showing the li item being moved below the v-for comment line : https://imgur.com/a/I1Odo

Here's a pen reproducing our setup : https://codepen.io/Leotomas/pen/veayav?editors=1111

And here's a little video showing the bug : https://www.youtube.com/watch?v=2jhnJ9adrWM&feature=youtu.be

We have found a workaround. In the method that pushes the new item inside the list, we toggle the visibility of the list with a v-if, when then list reappears the dom issue is resolved.

addTask(instance) {                                                                                                                                                                                                                                         
                   let i = _.findIndex(this.data.instances, {id: instance.id});                                                                                                                                                                                            
                   let item = {                                                                                                                                                                                                                                            
                       id: uuid.v4(),                                                                                                                                                                                                                                      
                       libelle: instance.__new_item,                                                                                                                                                                                                                       
                       checked: false                                                                                                                                                                                                                                      
                   }                                                                                                                                                                                                                                                       
                   let p =  this._clone(this.data.instances[i].taches);                                                                                                                                                                                                    
                   p.push(item);                                                                                                                                                                                                                                           
                   this.states.ready = false;                                                                                                                                                                                                                              
                   this.$nextTick(() => {                                                                                                                                                                                                                                  
                       this.states.ready = true;                                                                                                                                                                                                                           
                       this.$set('data.instances[' + i +'].taches', p);                                                                                                                                                                                                    
                       instance.__new_item = null;                                                                                                                                                                                                                         
                   });                                                                                                                                                                                                                                                     
               },

So it seems that when sortable moves any item in the last position, the relationship between vue and the DOM is broken somehow.

Thanks in advance

rafatrace commented 6 years ago

This happens to me too, have you managed to find a solution @Leotomas ?

Leotomas commented 6 years ago

@rafamds yes as written above, "we have found a workaround". To explain further :

It somehow resets the dom properly and the bug goes away.

bradlis7 commented 6 years ago

I was having this problem as well... I would make a bet that the rubaxa is applying the sort to the DOM, and then when Vue tries to reorder, it's using "in-place patch strategy".

@Leotomas solution causes Vue to recreate the DOM, which is probably fine.

The best solution may be to provide a key attribute with v-for (https://vuejs.org/v2/guide/list.html#key).

There might be a fix that this library can make so that rubaxa doesn't actually update the DOM, but I have not looked into it that far.