Vue-dropzone: Using a fully featured vue component as the preview template

Created on 2 Aug 2017  路  8Comments  路  Source: rowanwins/vue-dropzone

Description:

For the purposes of keeping code DRY I'd like to use the html from a existing component as the preview template.
Right now, at least according to the documentation I was able to find we are supposed to give the previewTemplate prop a function that returns HTML.
I think it would be nicer if it were possible to use a component that was for instance imported from a .vue file.

Steps To Reproduce:

I've tried to import the component and attach it to the data property of the parent that contains the vue2-dropzone component.
Passing the data property itself or something akin to

<dropzone :previewTemplate="previewTemplate.render">

does not work, as the render function has not been created when the dropzone component is loaded.
It probably shouldn't, but maybe there is a way?

awaiting feedback enhancement

Most helpful comment

@rowanwins @pscheit I have found a way to use components as previewTemplates.

The basic gist of it is to delay the initial VueDropzone component creation until you have the raw preview template html.

So this is what I did.

By default, I prevent the vue-dropzone from being loaded:

<vue-dropzone v-if="!loading"...
...
data: () => ({
  loading: true,
  previewHtml: null,

I load my options prop through computed properties but it should work if you load them through data:

computed: {
  options() {
    return {
      url: `${process.env.VUE_APP_API_BASE_URL}/upload`,
      previewTemplate: this.previewHtml,
    };
  },
},

Then I import Vue and my preview template component:

import Vue from 'vue';
import vue2Dropzone from 'vue2-dropzone';
import PreviewTemplate from './upload-media/PreviewTemplate.vue';

The preview component is a simple template with data-dz-* attributes in place where I want them.
For example this is my PreviewTemplate component (with Vuetify):

<template>
  <v-card>
    <v-list-item three-line>
      <v-list-item-avatar size="125" tile>
        <div data-dz-thumbnail-bg></div>
      </v-list-item-avatar>
      <v-list-item-content class="align-self-start">
        <v-list-item-title class="headline mb-2"><span data-dz-name></span></v-list-item-title>
        <v-list-item-subtitle><span data-dz-size></span></v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>
  </v-card>
</template>

<script>
export default {};
</script>

Finally, I mount an instance of the component in my created hook and then pull out its outerHTML, load it into my previewHtml data attribute and end the loading:

created() {
  const ComponentClass = Vue.extend(PreviewTemplate);
  const instance = new ComponentClass();
  instance.$mount();
  this.previewHtml = instance.$el.outerHTML;

  this.loading = false;
}

Now when Dropzone starts initialising, I already have a compiled previewTemplate HTML in my options prop and it works like a charm.

If you want, I can make it into a PR.

All 8 comments

Gday @NikiSchlifke

That would be awesome, there's been some related requests (eg here ). I definitely love to do this but I haven't found a way yet. I gather it is complicated downstream but how dropzone.js itself handles the html string that is parsed, when I was digging I found reference to someone from the angular community wanting to do something similar.

Anyway I haven't given up hope yet, Im currently working on an overhaul of this component so Im trying to work it into that.

Hi folks,

Version 3 is now released. Check out the new docs for more info.

@rowanwins you got any progress on this? I tried to have a look at it, but didn't get any angle. I'm not that keen in vue yet, but you got any tips where we can start to solve this issue?

Unfortunately not @pscheit - it's a tricky one that I think is dependent on some changes upstream in dropzone itself.

@rowanwins @pscheit I have found a way to use components as previewTemplates.

The basic gist of it is to delay the initial VueDropzone component creation until you have the raw preview template html.

So this is what I did.

By default, I prevent the vue-dropzone from being loaded:

<vue-dropzone v-if="!loading"...
...
data: () => ({
  loading: true,
  previewHtml: null,

I load my options prop through computed properties but it should work if you load them through data:

computed: {
  options() {
    return {
      url: `${process.env.VUE_APP_API_BASE_URL}/upload`,
      previewTemplate: this.previewHtml,
    };
  },
},

Then I import Vue and my preview template component:

import Vue from 'vue';
import vue2Dropzone from 'vue2-dropzone';
import PreviewTemplate from './upload-media/PreviewTemplate.vue';

The preview component is a simple template with data-dz-* attributes in place where I want them.
For example this is my PreviewTemplate component (with Vuetify):

<template>
  <v-card>
    <v-list-item three-line>
      <v-list-item-avatar size="125" tile>
        <div data-dz-thumbnail-bg></div>
      </v-list-item-avatar>
      <v-list-item-content class="align-self-start">
        <v-list-item-title class="headline mb-2"><span data-dz-name></span></v-list-item-title>
        <v-list-item-subtitle><span data-dz-size></span></v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>
  </v-card>
</template>

<script>
export default {};
</script>

Finally, I mount an instance of the component in my created hook and then pull out its outerHTML, load it into my previewHtml data attribute and end the loading:

created() {
  const ComponentClass = Vue.extend(PreviewTemplate);
  const instance = new ComponentClass();
  instance.$mount();
  this.previewHtml = instance.$el.outerHTML;

  this.loading = false;
}

Now when Dropzone starts initialising, I already have a compiled previewTemplate HTML in my options prop and it works like a charm.

If you want, I can make it into a PR.

@rowanwins @vrajroham
If this is still relevant I've made a way to get "proper" reactive templating for dropzone
https://github.com/AlexanderYW/vue-dropzone

And by "proper" i still need to figure out a way to deal with HUGE images without loosing performance (Will look into scaling the images before converting them to base64), but long story short I made it work with slots where it does not loose the @click bindings when being rendered

Feel free to give a hand if you have idea's regarding the performance issues

Hi AlexanderYW

I made it work with slots where it does not loose the @click bindings when being rendered

This is awesome, actually is exactly what is working on but got stuck as I kept loosing the @click binding inside slot,

Can u pls plz create a demo ASAP on codesandbox or codepen. Already spent almost 2 weeks on this and other related issues, trying to make it work.

Thanks

@rowanwins @vrajroham
If this is still relevant I've made a way to get "proper" reactive templating for dropzone
https://github.com/AlexanderYW/vue-dropzone

And by "proper" i still need to figure out a way to deal with HUGE images without loosing performance (Will look into scaling the images before converting them to base64), but long story short I made it work with slots where it does not loose the @click bindings when being rendered

Feel free to give a hand if you have idea's regarding the performance issues

Unfortunately this does not work, at first your changed library refused to work at all, I fixed it, but it turned out that it does not support an external container for the template

Was this page helpful?
0 / 5 - 0 ratings