Skip to content

Instantly share code, notes, and snippets.

@rnovec
Created July 30, 2021 23:24
Show Gist options
  • Select an option

  • Save rnovec/65a91c8f3eb4dedb3af43a710adbca39 to your computer and use it in GitHub Desktop.

Select an option

Save rnovec/65a91c8f3eb4dedb3af43a710adbca39 to your computer and use it in GitHub Desktop.
Upload Excel and convert to JSON with Vue.js 2
<template>
<!-- REPLACE WITH YOUR INPUT FILE TAG/COMPONENT -->
<div>
<b-field class="m-4">
<b-upload @input="handleUpload" v-model="dropFiles" multiple drag-drop expanded>
<section class="section">
<div class="content has-text-centered">
<p>
<b-icon icon="upload" size="is-large"></b-icon>
</p>
<p>Suelta tus archivos aquí o haz clic para subir</p>
</div>
</section>
</b-upload>
</b-field>
<div class="tags m-4">
<span class="tag is-primary" v-for="(file, index) in dropFiles" :key="index">
{{ file.name }}
<button
class="delete is-small"
type="button"
@click="deleteDropFile(index)"
></button>
</span>
</div>
</div>
</template>
<script>
import XLSX from 'xlsx'
export default {
props: {
beforeUpload: Function, // eslint-disable-line
onSuccess: Function // eslint-disable-line
},
data () {
return {
loading: false,
dropFiles: [],
lastFile: null,
excelData: {
file: null,
header: null,
results: null
}
}
},
methods: {
generateData ({ header, results }) {
this.excelData.file = this.dropFiles[this.dropFiles.length - 1]
this.excelData.header = header
this.excelData.results = results
this.onSuccess && this.onSuccess(this.excelData)
},
handleUpload (e) {
if (this.loading) return
const files = this.dropFiles
// if (files.length !== 1) {
// this.$buefy.toast.open('Only support uploading one file!')
// return
// }
const rawFile = files[0] // only use files[0]
if (!this.isExcel(rawFile)) {
this.$buefy.toast.open(
'Only supports upload .xlsx, .xls, .csv suffix files'
)
return false
}
this.upload(rawFile)
},
upload (rawFile) {
if (!this.beforeUpload) {
this.readerData(rawFile)
return
}
const before = this.beforeUpload(rawFile)
if (before) {
this.readerData(rawFile)
}
},
readerData (rawFile) {
this.loading = true
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = e => {
const data = e.target.result
const workbook = XLSX.read(data, { type: 'array' })
const firstSheetName = workbook.SheetNames[0]
const worksheet = workbook.Sheets[firstSheetName]
const header = this.getHeaderRow(worksheet)
const results = XLSX.utils.sheet_to_json(worksheet)
this.generateData({ header, results })
this.loading = false
resolve()
}
reader.readAsArrayBuffer(rawFile)
})
},
getHeaderRow (sheet) {
const headers = []
const range = XLSX.utils.decode_range(sheet['!ref'])
let C
const R = range.s.r
/* start in the first row */
for (C = range.s.c; C <= range.e.c; ++C) {
/* walk every column in the range */
const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
/* find the cell in the first row */
let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
headers.push(hdr)
}
return headers
},
isExcel (file) {
return /\.(xlsx|xls|csv)$/.test(file.name)
},
deleteDropFile (index) {
this.dropFiles.splice(index, 1)
}
}
}
</script>
@rnovec
Copy link
Author

rnovec commented Jul 30, 2021

Usage

Template

<upload-excel-component
              ref="fileUpload"
              :on-success="handleSuccess"
              :before-upload="beforeUpload"
            />

Script

...
methods: {
    beforeUpload () {
      return true
    },
    handleSuccess ({ results, header, file }) {
      console.log(results, header, file)
      this.tables.push({
        file,
        data: results,
        headers: header.map(el => {
          return {
            field: el,
            label: el,
            visible: true,
            cellClass: 'is-size-7',
            headerClass: 'has-text-dark is-size-7'
          }
        })
      })
    },
}
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment