Vue.Draggable icon indicating copy to clipboard operation
Vue.Draggable copied to clipboard

Deleting item within a draggable element continues dragging

Open tanhuakun opened this issue 4 years ago • 0 comments

The problem:

I have a list of questions that is draggable. Within each draggable item, I have a delete button that removes a subitem.

On clicking the delete button, the drag continues.

Note: This only happens with forceFallback = true.

The gif below shows me clicking the deleting button. After the click, my left mouse button is up. However, the dragging remains draggableExample

My code is here:

<template>
  <div>
    <div class="mb-2">
      Custom form builder, drag and drop to rearrange.
    </div>
    <draggable
      v-model="questions"
      :scrollSensitivity="300"
      :force-fallback="true"
    >
      <transition-group>
        <div
          v-for="(question, index) in questions"
          :key="index"
          class="bg-white rounded-md px-3 pt-2 pb-2 mb-3 cursor-move"
        >
          <div class="font-bold ml-1 mb-1">Question {{ index + 1 }}</div>
          <v-row>
            <v-col cols="12" sm="7">
              <v-text-field
                dense
                outlined
                label="Question"
                v-model="question.question"
              />
              <v-select
                :items="inputType"
                dense
                outlined
                label="Input Type"
                v-model="question.type"
                @change="changeQuestionType($event, index)"
              />
              <div v-if="question.type == 'text'">
                <v-select
                  :items="textConstraints"
                  dense
                  outlined
                  label="Text Constraints"
                  v-model="question.constraints"
                />
              </div>
              <div v-if="question.type == 'radio'">
                <v-text-field
                  v-for="(option, index) in question.options"
                  :key="index"
                  dense
                  outlined
                  :label="'Option ' + (index + 1)"
                  v-model="question.options[index]"
                  :append-icon="question.options.length > 1 ? 'mdi-delete' : ''"
                  @click:append="deleteOption(question.options, index)"              <-- CLICKING THIS WILL CAUSE THE DRAG
                />
                <div class="flex flex-row">
                  <v-btn
                    class="primary ml-auto"
                    @click="addOption(question.options)"
                    >Add Option</v-btn
                  >
                </div>
              </div>
              <div v-if="question.type == 'checkbox'">
                <v-text-field
                  v-for="(option, index) in question.options"
                  :key="index"
                  dense
                  outlined
                  :label="'Option ' + (index + 1)"
                  v-model="question.options[index]"
                  :append-icon="question.options.length > 1 ? 'mdi-delete' : ''"
                  @click:append="deleteOption(question.options, index)"
                />
                <div class="flex flex-row">
                  <v-btn
                    class="primary ml-auto"
                    @click="addOption(question.options)"
                    >Add Option</v-btn
                  >
                </div>
              </div>
            </v-col>
          </v-row>
        </div>
      </transition-group>
    </draggable>
    <v-btn color="primary" class="mb-1 px-6" @click.stop="addQuestion">
      <span style="text-transform: initial; font-size:16px;">
        Add Question
      </span>
    </v-btn>
  </div>
</template>

<script>
import draggable from "vuedraggable";
// import Vue from "vue";

export default {
  components: {
    draggable
  },
  data: function() {
    return {
      inputType: ["radio", "checkbox", "text"],
      textConstraints: ["text", "number"],
      questions: [],
      baseQuestions: ["question", "type"], // inputs that all questions will have
      inputSpecificQuestions: {
        // so far only have default primitive or array with primitive values :)
        text: [{ key: "constraints", default: "" }],
        checkbox: [{ key: "options", default: [""] }],
        radio: [{ key: "options", default: [""] }]
      }
    };
  },
  methods: {
    addQuestion() {
      this.questions.push({
        type: "text",
        question: "",
        constraints: "String"
      });
    },
    addOption(optionArray) {
      optionArray.push("");
    },
    deleteOption(optionArray, index) {
      optionArray.splice(index, 1);
    },
    changeQuestionType(value, index) {
      let question = this.questions[index];
      for (const key in question) {
        // remove all other questions!
        if (this.baseQuestions.indexOf(key) == -1) {
          delete question[key];
        }
      }

      this.inputSpecificQuestions[value].forEach(inputs => {
        if (Array.isArray(inputs.default)) {
          // does a deep copy of the array
          let newArr = [];
          inputs.default.forEach(item => {
            newArr.push(item);
          });
          this.$set(question, inputs.key, newArr);
        } else {
          this.$set(question, inputs.key, inputs.default);
        }
      });
      this.questions[index] = question;
      console.log(this.questions);
    },
  }
};
</script>

I am in need of a way to cancel the drag on click. Is there an event I can fire to do that?

Edit: This is on google chrome on windows 10

Using Vue 2.X and vuedraggable 2.24.3

tanhuakun avatar Feb 03 '22 05:02 tanhuakun