vuetifyjs / vuetify

🐉 Vue Component Framework
https://vuetifyjs.com
MIT License
39.79k stars 6.96k forks source link

[Feature Request] Uploader component #238

Closed amesas closed 5 years ago

amesas commented 7 years ago

A file uploader component like:

http://element.eleme.io/#/en-US/component/upload

Async, progress, multiple file upload, etc....

dohomi commented 7 years ago

Here a proof of concept:

<template>
    <div>
        <v-text-field prepend-icon="attach_file" single-line
                      v-model="filename" :label="label" :required="required"
                      @click.native="onFocus"
                      :disabled="disabled" ref="fileTextField"></v-text-field>
        <input type="file" :accept="accept" :multiple="false" :disabled="disabled"
               ref="fileInput" @change="onFileChange">
    </div>
</template>
<script>
    export default{
        props: {
            value: {
                type: [Array, String]
            },
            accept: {
                type: String,
                default: "*"
            },
            label: {
                type: String,
                default: "Please choose..."
            },
            required: {
                type: Boolean,
                default: false
            },
            disabled: {
                type: Boolean,
                default: false
            },
            multiple: {
                type: Boolean, // not yet possible because of data
                default: false
            }
        },
        data(){
            return {
                filename: ""
            };
        },
        watch: {
            value(v){
                this.filename = v;
            }
        },
        mounted() {
            this.filename = this.value;
        },

        methods: {
            getFormData(files){
                const data = new FormData();
                [...files].forEach(file => {
                    data.append('data', file, file.name); // currently only one file at a time
                });
                return data;
            },
            onFocus(){
                if (!this.disabled) {
                    debugger;
                    this.$refs.fileInput.click();
                }
            },
            onFileChange($event){
                const files = $event.target.files || $event.dataTransfer.files;
                const form = this.getFormData(files);
                if (files) {
                    if (files.length > 0) {
                        this.filename = [...files].map(file => file.name).join(', ');
                    } else {
                        this.filename = null;
                    }
                } else {
                    this.filename = $event.target.value.split('\\').pop();
                }
                this.$emit('input', this.filename);
                this.$emit('formData', form);
            }
        }
    };
</script>
<style scoped>
    input[type=file] {
        position: absolute;
        left: -99999px;
    }
</style>
abotsi commented 7 years ago

Input(type=file) sounds like a must have! Doesn't it exists already? What is the link with this repo https://github.com/johnleider/vue-materials/blob/master/src/components/file-input.vue?

amesas commented 7 years ago

I was thinking about more feature complete solution:

Like: http://demo.geekslabs.com/materialize-v1.0/form-file-uploads.html https://github.com/shuyu/angular-material-fileinput

johnleider commented 7 years ago

As of right now, this will not be done for the core of Vuetify.

Darkside73 commented 7 years ago

@dohomi Thanks for sharing. I've ended up with the following:

getFormData (files) {
  const data = new FormData()
  for (let file of files) {
    data.append('files[]', file, file.name)
  }
  return data
}

And it plays with multiple nicely

jannhama commented 7 years ago

Here is small class for selecting file: https://github.com/jannhama/vuetify-upload-btn

jofftiquez commented 7 years ago

+1M

johnleider commented 7 years ago

I should have elaborated on my comment above. This will not be in the core of Vuetify, as far as the extensive functionality. However, we will include something like this in the addon packs that will come after Vuetify's release.

-edit- Forget this

jofftiquez commented 7 years ago

Hi @johnleider may we know the reason why? Coz it seems to be a pretty solid feature to have.

johnleider commented 7 years ago

Disregard my comment, we'll do it, but after the core components are complete.

jofftiquez commented 7 years ago

@johnleider WHOAH! You da real MVP. Thanks :+1:

dohomi commented 7 years ago

@jofftiquez meanwhile you can check this one out: https://gist.github.com/dohomi/2bba9e2905d00cd1cec9c09cfd87bd10

jofftiquez commented 7 years ago

I certainly will @dohomi thanks a lot. :)

lobosan commented 7 years ago

I think many of us need this essential component, thanks in advance for adding this feature ;)

johnleider commented 7 years ago

This will be something that will be included in the front end package development.

mstaack commented 7 years ago

i can highly recommend: this for file/folder handling: https://github.com/silverwind/uppie and this for generell vue upload needs: https://github.com/thetutlage/vue-clip

Tabrizian commented 7 years ago

When will you add this feature? A must have.

johnleider commented 7 years ago

Planned for the front end component pack

On Aug 17, 2017 4:30 AM, "Iman Tabrizian" notifications@github.com wrote:

When will you add this feature? A must have.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/vuetifyjs/vuetify/issues/238#issuecomment-323004428, or mute the thread https://github.com/notifications/unsubscribe-auth/AIpOgol30Eat_cuj9OIC8cRSnSI8dM89ks5sY_oKgaJpZM4Mig7T .

spaquet commented 7 years ago

@mstaack Agre that http://vueclip.adonisjs.com/ is great to consider. It just need a nice UI out of the box.

arpitprod commented 7 years ago

we need to add/update code in 'webpack.base.config.js' file for use vue-clip

module.exports = {
  resolve: {
    alias: {
      'vue': 'vue/dist/vue.js', // add for image upload things for use vue component in vue 2
    }
  },
Tabrizian commented 7 years ago

vueclip has only one version released? And its last update is 9 months ago! A risk to start using it.

KaelWD commented 7 years ago

@37ch4 @Gab0o777 @Mehtrick @mklemenz @efriedli Cut it out with the +1 comments please, there's a button for that.

Tabrizian commented 7 years ago

We're still waiting for it

johnleider commented 7 years ago

Let's drop this conversation please. I've already tagged this with the Front-end pack milestone. This is also outlined here: https://vuetifyjs.com/vuetify/roadmap

We are going to do it, thank you for your patience.

Tabrizian commented 7 years ago

If there is any help need I'm ready to help actually :)

johnleider commented 7 years ago

Hop on: https://discord.gg/CvXCKc

nasirouwagana commented 6 years ago

Here is below an image uploader component : file-input.vue

image-file-input-1

image-file-input-2

<template>
    <div>
        <div>
            <img
                    :src="imageUrl"
                    ref="imageUrl"
                    height="150"
                    @click="onPickFile"
                    style="cursor: pointer;"
            >
        </div>
        <div>
            <v-btn raised @click="onPickFile" v-if="!imageUrl">
                {{ selectLabel }}
            </v-btn>
            <v-btn raised class="error" @click="removeFile" v-else>
                {{ removeLabel }}
            </v-btn>
            <input
                    type="file"
                    ref="image"
                    name="image"
                    :accept="accept"
                    @change="onFilePicked"
            >
        </div>
    </div>
</template>

<script>
    export default {
        props: {
            value: {
                type: String
            },
            accept: {
                type: String,
                default: '*'
            },
            selectLabel: {
                type: String,
                default: 'Select an image'
            },
            removeLabel: {
                type: String,
                default: 'Remove'
            }
        },

        data() {
            return {
                imageUrl: ''
            }
        },

        watch: {
            value(v) {
                this.imageUrl = v
            }
        },

        mounted() {
            this.imageUrl = this.value
        },

        methods: {
            onPickFile() {
                this.$refs.image.click()
            },

            onFilePicked(event) {
                const files = event.target.files || event.dataTransfer.files

                if (files && files[0]) {
                    let filename = files[0].name

                    if (filename && filename.lastIndexOf('.') <= 0) {
                        return //return alert('Please add a valid image!')
                    }

                    const fileReader = new FileReader()
                    fileReader.addEventListener('load', () => {
                        this.imageUrl = fileReader.result
                    })
                    fileReader.readAsDataURL(files[0])

                    this.$emit('input', files[0])
                }
            },

            removeFile() {
                this.imageUrl = ''
            }
        }
    }
</script>

<style scoped>
    input[type=file] {
        position: absolute;
        left: -99999px;
    }
</style>

As example, It can be used in a form like this :

<template>
  <v-container>
     <v-card>
       <form @submit.prevent="onSubmit">
           <v-layout row>
                  <v-flex xs12>
                           <file-input
                               accept="image/*"
                               ref="fileInput"
                              @input="getUploadedFile"
                          ></file-input>
                  </v-flex>
          </v-layout>
          <v-layout row>
                <v-flex xs12>
                     <v-btn
                        class="primary"
                         type="submit"
                       >
                           Save
                       </v-btn>
                    </v-flex>
          </v-layout>
       </form>
     </v-card>
  </v-container>
</template>

<script>
    import axios from 'axios'
    import FileInput from '../../components/FileInput.vue'

    export default {
        components: {FileInput},

        data() {
            return {
                image: '',
                title: '',
                description: ''
            }
        },

        methods: {
            getUploadedFile(e) {
                this.image = e
            },
            onSubmit() {
                 let formData = new FormData()
                 formData.set('image', this.image)
                 formData.set('title', this.title)
                 formData.set('description', this.description)

                 axios.post('/api/posts', formData)
                       .then(response => {
                            // Any Code
                        })
                       .catch(error => {
                            // Any Code
                        })
            }
       }
   }
</script>
jzs11 commented 6 years ago

Here is an uploader component I create which inspired by v-text-field

uploader

lobo-tuerto commented 6 years ago

@jingzheshan where is the code? :P

jzs11 commented 6 years ago

@lobo-tuerto thanks for the interests, I feel very hard to share the whole code with limited time. I may write one article when I am free but here is a really rough vue template of what I am using. Hope it can give you some ideas : )

image

dohomi commented 6 years ago

here is a complete upload widget for the graph.cool API: https://gist.github.com/dohomi/8f27b14ce5d0c2923ed5c88a55ea582f

signalkuppe commented 6 years ago

Just published this for cloudinary images https://github.com/signalkuppe/vuetify-cloudinary-upload

cb109 commented 6 years ago

Although I'd love to have a prebuilt upload component, I guess it won't be easy to create one that fits most users needs in terms of behaviour and looks. Fortunately it is very much possible already to build uploaders with existing vuetify components. I'll just throw ours into the mix of inspirationals here:

multi-uploader

dohomi commented 6 years ago

Here is an interesting project maybe it is useful for someone: https://github.com/transloadit/uppy

ecmel commented 6 years ago

My component for file selection https://gist.github.com/ecmel/3d3d918f403140ff563d274c773508bf

aaarghhh commented 6 years ago

https://rowanwins.github.io/vue-dropzone/ :heart:

chris104957 commented 6 years ago

my version, in case its of any use to anyone https://gist.github.com/chris104957/94fced8071b81cb980e461bf44e51273

forresthopkinsa commented 6 years ago

I'm using this: https://github.com/doritobandito/vuetify-upload-button

It's the best option I've found, including the ones in this thread.

sammy2077 commented 6 years ago

You can wrap v-progress-linear inside v-text-field as below fileinput

LoveMeWithoutAll commented 6 years ago

This is my component' gist. It works on Firebase Cloud storage

demo

outluch commented 6 years ago

It's the best option I've found, including the ones in this thread. Ok, guys, if it is the best option out there, take a look here, please.

https://www.npmjs.com/package/@outluch/v-file https://github.com/outluch/v-file

Why we pass all that props to some hacked v-label in that component, when we can just pass our button in the slot and connect @click event to hidden <input type="file">? Any ideas how to improve are welcome.

cby016 commented 5 years ago

Nice job @chris104957 - very easy to customize to fit my own needs.

I especially like the drag and drop functionality!

yoldar commented 5 years ago

Finally, did what needed for file uploader and downloader. Based on http://uppy.io/ and https://github.com/sachinchoolur/lightgallery.js and https://www.minio.io/. Contain auto thumbnail resizing after upload.

https://cdn.discordapp.com/attachments/342730702091059212/497699065145065482/Uploader__Downloader.gif

desthercz commented 5 years ago

Will there be an official component or not?

peluprvi commented 5 years ago

TL;DR: Yes

It's in this milestone and on Vuetify Roadmap. It is one of the most required components. So, it will appear sometime.

ivaaaan commented 5 years ago

Any news? I do not see it in the Roadmap

MajesticPotatoe commented 5 years ago

Indeterminate. Was slated for 1.5 but was canceled to focus on 2.0 release. Will probably be included in 2.0 or shortly after 2.0.

nni123 commented 5 years ago

very disappointed...since 2017 they're pushing away simple yet important component...ah well pain of open source..take it or leave it or get a lecture from the creator (not sorry for the comment)

in fact, a few custom solution from the third-party looks good

johnleider commented 5 years ago

Thank you all for being patient with this. I currently have a branch here https://github.com/vuetifyjs/vuetify/tree/feat/%23238-file-upload that I will work on next week and get it in as part of a future update. I don't think it will be 1.6 as we are prepping for LTS, but I'll poll the team.

jofftiquez commented 5 years ago

@nni123 submit a PR. LOL.