Skip to content

Instantly share code, notes, and snippets.

@dohomi
Last active January 13, 2019 09:23
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dohomi/8f27b14ce5d0c2923ed5c88a55ea582f to your computer and use it in GitHub Desktop.
Save dohomi/8f27b14ce5d0c2923ed5c88a55ea582f to your computer and use it in GitHub Desktop.
File container for vuetify and graph.cool. It lists files provided by a prop with link to the public url. Below it shows a file upload field
<template>
<div>
<h3 class="subheading" v-if="!hideLabel">{{label}}</h3>
<v-list v-if="mediaList">
<v-list-tile v-for="(item,i) in mediaList" :key="i">
<v-list-tile-avatar @click="onItemClick(item.url)">
<img :src="item.url" :alt="item.name" :title="item.name"/>
</v-list-tile-avatar>
<v-list-tile-content @click="onItemClick(item.url)">
<v-list-tile-title>{{item.contentType}}</v-list-tile-title>
<v-list-tile-sub-title>{{item.name}}</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
<v-btn icon
@click.native="deleteFile(item.id)"
:disabled="$store.state.mediaDeleting">
<v-icon class="red--text text--lighten-1">delete</v-icon>
</v-btn>
</v-list-tile-action>
</v-list-tile>
</v-list>
<v-progress-linear class="ma-0"
:active="isActive"
:indeterminate="true"></v-progress-linear>
<v-layout row v-if="(!multiple && !mediaList) || multiple">
<v-text-field prepend-icon="attach_file"
single-line
:value="filename"
:label="label"
:disabled="disabled"
:required="required"
@click.native="onFocus"
ref="fileTextField"></v-text-field>
<input type="file"
:accept="accept"
:multiple="multiple"
:disabled="disabled"
ref="fileInput" @change="onFileChange">
<v-btn icon
class="primary--text mt-4"
:disabled="!filename"
@click.stop="fileUpload"
:loading="uploading">
<v-icon>file_upload</v-icon>
</v-btn>
</v-layout>
</div>
</template>
<script>
export default {
name: 'upload-container',
props: {
accept: {
type: String,
'default': '*'
},
label: {
type: String,
'default': 'File Upload'
},
disabled: Boolean,
multiple: Boolean,
required: Boolean,
media: Array | Object,
deletingFile: Boolean | Object,
hideLabel: Boolean
},
data () {
return {
filename: '',
forms: [],
uploading: false
}
},
computed: {
isActive () {
return this.$store.state.mediaDeleting || this.uploading
},
mediaList () {
if (!this.media) return null
if (this.media.constructor === Object) {
return [this.media]
}
const filter = this.media && this.media.filter(e => e)
return filter.length ? filter : null
}
},
methods: {
onItemClick (url) {
window.open(url, '_blank')
},
async deleteFile (fileId) {
this.$emit('deleted', fileId)
},
async fileUpload () {
const endpoint = `https://api.graph.cool/file/v1/${process.env.GRAPH_FILE_API}`
if (this.forms.length) {
this.uploading = true
const results = []
for (const form of this.forms) {
const response = await fetch(endpoint, {method: 'POST', body: form})
const responseData = await response.json()
results.push(responseData)
}
this.uploading = false
this.forms = []
this.filename = ''
const data = results.length === 1 ? results[0] : results
if (results.length) {
this.$emit('uploaded', data)
}
}
},
getFormData (files) {
const forms = []
for (const file of files) {
const form = new FormData()
form.append('data', file, file.name)
forms.push(form)
}
return forms
},
onFocus () {
if (!this.disabled) {
this.$refs.fileInput.click()
}
},
onFileChange ($event) {
const files = $event.target.files || $event.dataTransfer.files
let filename
if (files) {
if (files.length > 0) {
filename = [...files].map(file => file.name).join(', ')
}
} else {
filename = $event.target.value.split('\\').pop()
}
this.$refs.fileTextField.inputValue = filename
this.filename = filename
this.forms = this.getFormData(files)
}
}
}
</script>
<style scoped>
input[type=file] {
position: absolute;
left: -99999px;
}
</style>
<template>
Make use of the file upload container:
<file-container
:media="media"
@uploaded="onUploaded"
@deleted="onFileDeleted"></file-container>
</template>
<script>
export default{
components:{FileContainer},
computed:{
media(){
return [] // => here you can map the media and send it to the container
}
}
methods:{
onFileDeleted(fileId){
console.log(fileId) // => this fileId got deleted
},
onUploaded(payload){
console.log(payload) // => here is the file information (either array or object of uploaded files
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment