0

I have the following Vue component and when I drag Item A into the second drop div it does not render Item A in the second drop div and I notice that the computed listOne and listTwo are not re-computed. If I run the same code contained in onDrop in the DevTools console at the breakpoint: this.$set(this.items, itemID, {id: itemID, list: list, title: this.items.find(item => item.id == itemID).title});, then continue, the computed listOne and listTwo are re-computed and Item A renders in the second drop div as expected. As I understand it, there are caveats to working with lists and computed props which this.$set is supposed to solve so, what am I doing wrong here?

<template>
  <div>
    <div
          class='drop-zone'
          @drop='onDrop($event, 1)' 
          @dragover.prevent
          @dragenter.prevent
    >
      <div 
              class='drag-el' 
              v-for='item in listOne' 
              :key='item.title' 
              draggable
              @dragstart='startDrag($event, item)'
       >
        {{ item.title }}
      </div>
    </div>
    <div
          class='drop-zone'
          @drop='onDrop($event, 2)' 
          @dragover.prevent
          @dragenter.prevent
    >
      <div 
              class='drag-el' 
              v-for='item in listTwo' 
              :key='item.title' 
              draggable
              @dragstart='startDrag($event, item)'
       >
        {{ item.title }}
      </div>
    </div>
  </div>
</template>

<script>
  import { mapState } from 'vuex';
  
  export default {
    name: "Welcome",
    data () {
       return {
         items: [
         {
           id: 0,
           title: 'Item A',
           list: 1
         },
         {
           id: 1,
           title: 'Item B',
           list: 1
         },
         {
           id: 2,
           title: 'Item C',
           list: 2
         }]
       }
    },
    components: {},
    computed : {
        listOne: function() {
          this.items;
          debugger;
          return this.items.filter(item => item.list === 1);
        },
        listTwo: function() {
          this.items;
          debugger;
          return this.items.filter(item => item.list === 2);
        }
    },
    methods: {
      startDrag: (evt, item) => {
         evt.dataTransfer.dropEffect = 'move';
         evt.dataTransfer.effectAllowed = 'move';
         evt.dataTransfer.setData('itemID', item.id);
      },
      onDrop: (evt, list) => {
         const itemID = evt.dataTransfer.getData('itemID');
         debugger;
         const oldItem = this.items.find(item => item.id == itemID);
         const item = {id: itemID, list: list, title: oldItem.title};
         this.$set(this.items, itemID, item);
      }
    },
  }
</script>

<style scoped>
  .drop-zone {
    background-color: #eee;
    margin-bottom: 10px;
    padding: 10px;
  }

  .drag-el {
    background-color: #fff;
    margin-bottom: 10px;
    padding: 5px;
  }
  
</style>

  • 1
    In `this.$set(this.items, itemID, item)` the second parameter should be an index and not a prop of an item – Anatoly Dec 12 '20 at 20:01
  • Even if I hardcode the onDrop implementation to `this.$set(this.items, 0, {id: 0, list: 2, title: "Item A"})` it still does not re-compute. – user13393464 Dec 13 '20 at 01:20
  • 1
    Aha! I figured it out. The `this` inside the onDrop method was incorrectly scoped due to the onDrop being an arrow function. If the onDrop method is changed to a regular function than `this` is correctly scoped and it works as expected. Silly mistake on my part. `onDrop: function(evt, list)` – user13393464 Dec 13 '20 at 02:01

0 Answers0