Search code examples
vuejs3vuedraggable

How to use vuedraggable for an n x n grid of cells?


I have taken a simple sample from vue.draggable.next and converted it to use vuetify's v-btn. The resulting code works fine:

     <draggable
      :list="list"
      :item-key="name"
      class="list-group"
      ghost-class="ghost"
      :move="checkMove"
      :swap="true"
      @start="dragging = true"
      @end="dragging = false"
    >
      <template #item="{ element }">
        <v-btn  :class="{ 'not-draggable': !enabled }">
          {{ element.name }}
        </v-btn>
      </template>
    </draggable>

but in my actual app I don't want a simple word list; I am trying to use draggable for an array of images. But I don't know how to use the <template #item="{ element }"> construction for this type of data:

<draggable 
      :list="trackGrid"
      :move="checkMove"
      :swap="true"
      :item-key="getIndex">
      <template #item="{ element }"  v-for="(row,r) in trackGrid">
        <v-row  no-gutters >
        <template v-for="(cell,c) in row" :key="r*8 + c" >
          <div>
          <v-col width="40">
                <v-img v-if=" !cell.used" class="canDragIt"
                :src = cell.content
                  >
                </v-img>
                <v-img v-else class="cannotDrag"
                  :src =  cell.content
                  > 
                </v-img>
          </v-col>
        </div>
        </template>
      </v-row>
  </template>
  </draggable>

The cell images show up with this code, but the last row of the grid is repeated eight times, rather than displaying each row differently. Also, the VSCode editor tells me that

'element' is declared but its value is never read

(and the same for the row/col iterators in v-for).

The grid renders correctly without the <draggable> component. So, what am I doing incorrectly here? How do I use the {element} construct, and/or what else am I missing?


Solution

  • I have found a solution. The problem was that the draggable iterator <template #item="{ element }" > seems only capable of working in a column mode, not as rows, so is in effect incompatible with Vuetify's <v-row>. I had been trying to draw eight rows of images, with eight images in each row. What I am now doing is to draw eight columns of images , with eight images in each column:

    <v-row  style="max-width: 320px;" no-gutters>
      <v-col width="40" v-for="n in 8">
        <draggable 
          :list="trackGrid[n-1]"
          group="track"
          :move="checkMove"
          :swap="true"
          :item-key="getIndex">
          <template #item="{ element }"  >
            <div>
              <v-img v-if=" !element.used" class="canDragIt"  :src = element.content />
              <v-img v-else class="cannotDrag"   :src =  element.content /> 
            </div>
          </template>
        </draggable> 
      </v-col>
    </v-row>
    

    This solution requires the rather odd prerequisite of 'inverting' the original array, so that rows become columns and vice-versa.