Search code examples
javascriptvue.jsdropzone

Dropzone instance works on first element but not cloned elements (Vue)


I have a snippet below which is essentially my entire code block at this point, and essentially it creates a div and when you click "add another zone" it will clone that div. This allows the user to enter multiple lines of info and each have their own result and image.

The issue is that I'm successfully cloning everything with it's own unique identity thanks to my card setup. However, dropzone is not replicating. The first file dropzone form will work perfectly, but when I clone the div and have 2 or more dropzone insnstances on the page they don't work (they don't show the upload image text or anything)

How can I successfully apply my same logic to the dropzone instance here?

new Vue({
          components: {},
          el: "#commonNameDiv",
          data() {
            return {
              searchString: [''],
              results: [],
              savedAttributes: [],
              cards: [],
              showList: false,
              zoneNumber:[],
              imageZoneNames: []            }
          },
          methods: {
            autoComplete(ev, card) {
              this.results = [];
              console.log(this.searchString);
              if (ev.target.value.length > 2) {
                axios.get('/product/parts/components/search', {
                  params: {
                    searchString: ev.target.value
                  }
                }).then(response => {
                  card.results = response.data;
                  this.showList = true;
                  console.log(this.results);
                  console.log(this.searchString);
                });
              }
            },
            saveAttribute(result, card) {
              card.value = result.attribute_value;
              card.results = [];
              card.zone = this.zoneNumber;
              this.showList = false;
            },
            addCard: function() {
                this.cards.push({
                  index: "",
                  value: "",
                  zoneNumber: "",
                  results: [],
                  componentImage:""
                });

                console.log(this.cards);
            },
            hideDropdown() {
              this.showList = false;
            },

          },
          created() {

                this.addCard();

                let instance = this;

                Dropzone.options = {
                    maxFilesize: 12,
                    renameFile: function (file) {
                        var dt = new Date();
                        var time = dt.getTime();
                        return time + file.name;
                    },
                    acceptedFiles: ".jpeg,.jpg,.png,.gif",
                    addRemoveLinks: true,
                    timeout: 50000,
                    removedfile: function (file) {
                        console.log(file.upload.filename);
                        var name = file.upload.filename;

                        var fileRef;
                        return (fileRef = file.previewElement) != null ?
                            fileRef.parentNode.removeChild(file.previewElement) : void 0;

                    },
                    init: function() {
                        this.on("addedfile", 
                        function(file) { 
                            instance.imageZoneNames.push({name: file.upload.filename, desc: 'Line Drawing'});
                            console.log(file);
                            console.log(instance.imageZoneNames);
                        });
                    }
                };
                }
        })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.js"></script>


<div id="commonNameDiv">
<div class="uk-grid" v-for="(card, i) in cards" :key="i">
                    <div class="uk-width-1-10"  >
                        <input v-model=" card.zoneNumber" size="4" type="text" name="mapNumber">
                    </div>
                    <div class="uk-width-6-10">
                        <input
                          style="width:100%"
                          placeholder="what are you looking for?"
                          v-model="card.value"
                          v-on:keyup="autoComplete($event, card)"
                        >
                        <div v-if="showList"  class="panel-footer componentList" v-if="card.results.length">
                          <ul>
                            <li  v-for="(result, i) in card.results" :key="i">
                              <a v-on:click="saveAttribute(result, card)">@{{ result.attribute_value }}</a>
                            </li>
                          </ul>
                        </div>
                    </div>
                    <div class="uk-width-3-10">
                        <form method="post" action="{{url('product/parts/upload/store')}}" enctype="multipart/form-data"
                              class="dropzone">
                        </form>
                    </div>
                </div>

  <div style="height: 35px;">

  </div>

<div>
                    <a v-on:click="addCard">Add another zone</a>
                </div>
</div>


Solution

  • When you instantiate the Dropzone class, it automatically looks for elements to transform in dropzones (by default, elements with the .dropzone class).

    It looks like you want to dynamically add elements that are dropzones. Then you need to trigger the dropzone transformation yourself.

    I would suggest you disable the autoDiscover option, and manually designates each element you want to transform into dropzones :

    addCard() {
        this.cards.push({
        ...
        });
        let cardIndex = this.cards.length - 1;
    
        // Waiting for the element #dropzone-X to exist in DOM
        Vue.nextTick(function () {
            new Dropzone("#dropzone-"+cardIndex, {
               ...
            });
        });
    },
    created() {
        ...
        Dropzone.autoDiscover = false
        // no new Dropzone()
        ...
    
        // Starting setup
        this.addCard();
    },
    
    <form ... class="dropzone" v-bind:id="'dropzone-'+i">
    

    Working jsbin

    There are several ways to select the element to transform ($refs, ids, classes), here I'm suggesting ids.

    See the doc on programmatically creating dropzones