How I can upload files using Laravue with Dropzone - vue.js

i'm trying to make work Laravue Dropzone, but I have'nt working yet
Here is the code:
<el-dialog :title="'Importar Bitacora'" :visible.sync="dialogFormVisible">
<div v-loading="weblogCreating" class="form-container">
<el-form ref="weblogForm" :rules="rules" :model="newBitacora" label-position="left" label-width="150px">
<div class="editor-container">
<dropzone id="CargarBitacora" url="/api/bitacora/importar" #dropzone-removedFile="dropzoneR(e)" #dropzone-error="dropzoneError" #dropzone-success="dropzoneS" />
</div>
</el-form>
</div>
<div slot="footer" class="dialog-footer">
<el-button #click="dialogFormVisible = false">
{{ $t('bitacora.cancel') }}
</el-button>
<el-button type="primary" #click="handleUpload()">
{{ $t('bitacora.confirm') }}
</el-button>
</div>
</el-dialog>
<script>
import Dropzone from '#/components/Dropzone';
export default {
name: 'BitacoraList',
components: { Dropzone },
data() {
return {
files: [],
},
created() {
.. code here ..
},
methods: {
handleUpload(e) {
const formData = new FormData();
this.files.forEach(file => {
formData.append('files[]', file);
});
console.log(this.files);
},
}
};
</script>
I've tried to pass the files to handleUpload, but I can't make it work to the moment

I figured out how to upload files with dropzone, en the method handleUpload I just have to send the file to a post method in laravel backend who upload a temporary file
dropzoneR(file) {
var name = file.upload.filename;
fileResource.borrar(name).then(response => {
this.files.splice(this.files.indexOf(name), 1);
if (this.files.length < 1) {
this.btnUpload = true;
}
}).catch(error => {
console.log(error);
});
},
and returns an ok if it gets uploaded, then when I confirm thats the files I need up, other method in laravel backend who do what a want to do with the file if its an excel file (in mi case) upload the data to the database, or what ever I want. like this
async handleUpload(e) {
this.weblogCreating = true;
await bitacoraResource.store(this.files).then(response => {
this.$message({ message: 'Bitacoras importadas satisfactoriamente', type: 'success' });
this.files = '';
this.dialogImportVisible = false;
this.weblogCreating = false;
this.getList();
}).catch(error => {
this.$message({
message: 'Error importando las bitacoras ' + error.getMessage,
type: 'error',
});
this.weblogCreating = false;
console.log(error.message);
});
},

Related

Why label of file size on filepond show 1kb every file when displaying edit form?

I have a module that has add and edit form. In the add and edit form, the user can upload files. When edit, it will show uploaded files
In add form, it works. When user upload, file size of file displays file size correctly
But my problem is when edit form, each file displays 1kb file size on all files
You can see the problem here:
I use filepond package to upload files
My vue component like this :
<template>
<b-card>
<b-form #submit="onSubmit">
<b-row>
<b-col cols="8">
...
<b-form-group
id="fieldset-horizontal"
label-cols-sm="4"
label-cols-lg="2"
content-cols-sm
content-cols-lg="8"
label-for="description"
>
<template v-slot:label>
Description
</template>
<b-form-input id="description" v-model="description" required maxlength="100"></b-form-input>
</b-form-group>
<b-form-group
id="fieldset-horizontal"
label-cols-sm="4"
label-cols-lg="2"
content-cols-sm
content-cols-lg="9"
label-for="files"
>
<template v-slot:label>
Files
</template>
<file-pond v-if="this.$route.params.id"
label-idle='Drag and drop files here... or <span class="filepond--label-action"> Browse </span>'
v-bind:allow-multiple="true"
v-bind:server="server"
v-bind:files="files"
/>
<file-pond v-else
label-idle='Drag and drop files here... or <span class="filepond--label-action"> Browse </span>'
v-bind:allow-multiple="true"
accepted-file-types='application/pdf, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, .xlsx'
v-bind:server="server"
v-bind:required="true"
/>
</b-form-group>
</b-col>
<b-col cols="4">
<b-button type="submit" #click="save" variant="success">Save</b-button>
</b-col>
</b-row>
</b-form>
</b-card>
</template>
<script>
import { mapGetters, mapActions } from "vuex"
import vueFilePond from "vue-filepond"
...
export default {
data() {
return {
files: [],
server: {
process: (fieldName, file, metadata, load, error, progress, abort) => {
if(file.lastModified) {
if (this.dataFiles.findIndex(a => a.fileName == file.name) > -1) {
error(new Error('More than one file with the same name cannot be attached'));
}
else {
const data = new FormData()
data.append('files[]', file)
const CancelToken = axios.CancelToken
const source = CancelToken.source()
const config = {
method: 'post',
url: `${apiUrl}/upload`,
data : data,
cancelToken: source.token,
onUploadProgress: (e) => {
progress(e.lengthComputable, e.loaded, e.total)
},
}
axios(config)
.then(response => {
this.setSaveFile({
id: response.data.id,
name: response.data.name,
url: response.data.url,
})
load(response.data.id)
})
.catch((thrown) => {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message)
} else {
error('error')
}
})
return {
abort: () => {
source.cancel('Operation canceled by the user.')
}
}
}
}
else { /* this will show data file when edit data */
this.setSaveFile({
id: metadata.id,
name: metadata.name,
url: metadata.url,
})
load(metadata.id)
}
},
revert: (uniqueFileId, load, error) => {
const type = this.$route.params.id ? 'edit' : 'add'
this.setDeleteFile({id: uniqueFileId, type: type } )
error('error')
load()
},
},
}
},
async mounted() {
if(this.$route.params.id) {
await this.setEdit(this.$route.params.id)
}
},
computed: {
...mapGetters([
"dataFiles",
"dataEditSuccess",
])
},
watch: {
dataEditSuccess: {
handler(data) {
if (this.$route.params.id && data) {
this.showEditData()
}
},
immediate: true
}
},
methods: {
...mapActions([
"setSaveFile",
"setDeleteFile",
"setEdit",
]),
showEditData() {
const data = this.dataEditSuccess
this.description = data.description
for (let key in data.files) {
let filePost = {
source: data.files[key].name,
options: {
metadata: {
id: data.files[key].id,
name: data.files[key].name,
url: data.files[key].url,
},
},
}
this.files.push(filePost)
}
},
},
...
}
</script>
How can I solve this problem?
Note :
The docs : https://github.com/pqina/vue-filepond
Update :
I make my code in codesandbox like this : https://codesandbox.io/s/vue-filepond-live-demo-forked-0v3r3j
Here it looks the same file size
Actually I can uncomment this script to solve my problem :
file: {
name: this.filesFromApi[key].name,
size: this.filesFromApi[key].size,
},
But it makes me unable to fetch metadata in process. So process cannot be called. You can try it and see in the console log
If you're fetching some initial file metadata from an API, couldn't you add that data to vuex at mount time instead of trying to do it through filepond which would give you back the same metadata anyways? Regardless, perhaps listening to one of these events can help you.
in your component:
methods: {
onProcessFile(error, file) {
console.log('processed file metadata', file.getMetadata())
},
onAddFile(error, file) {
console.log('added file metadata', file.getMetadata())
}
},
<file-pond
name="test"
ref="pond"
#processfile="onProcessFile"
#addfile="onAddFile"
label-idle="Drop files here or <span class='filepond--label-action'>Browse</span>"
allow-multiple="true"
v-bind:files="myFiles"
v-bind:server="myServer"
/>

Tableau Vuejs getWorkBook() "Cannot read property get_workbook of null"

I am trying to follow the getData example found on the tableau javascript tutorial (https://github.com/tableau/js-api-samples/blob/master/getDataBasic.html) , but for vue js, however, I am unable to get it to work. I am able to render the tableau object, but when it comes to getting the underlying data or even trying to get the workbook name, I get the error: "Cannot read property get_workbook of null". Below is my code:
<template>
<div class="container" style="margin-top: 90px;">
<div id="vizContainer2"></div>
</div>
</template>
<script>
export default {
name: 'TableauHolder',
methods: {
getUnderlyingData(){
const containerDiv = document.getElementById("vizContainer2")
let url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms"
let options = {
hideTabs: true,
hideToolbar: true,
onFirstInteractive: () => {
}
}
this.viz = new window.tableau.Viz(containerDiv, url, options)
let sheet = this.viz.getWorkbook().getActiveSheet().getWorksheets().get("Storm Map Sheet")
console.log(sheet)
},
},
mounted () {
window.addEventListener('load', () => {
this.getUnderlyingData();
})
}
}
</script>
Placing getWorBbook() in onFirstInteractive successfully gets me the workbook name (as shown below), but I am not sure where to go from there in terms rendering the data.
<template>
<div class="container" style="margin-top: 90px;">
<div id="vizContainer2"></div>
</div>
</template>
<script>
export default {
name: 'TableauHolder',
methods: {
getUnderlyingData(){
const containerDiv = document.getElementById("vizContainer2")
let url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms"
let options = {
hideTabs: true,
hideToolbar: true,
onFirstInteractive: () => {
let sheet = this.viz.getWorkbook()
console.log(sheet)
}
}
this.viz = new window.tableau.Viz(containerDiv, url, options)
},
},
mounted () {
window.addEventListener('load', () => {
this.getUnderlyingData();
})
}
}
</script>
I realized that the JavaScript API is asynchronous and therefore the let sheet line is executed before while executing the API. Therefore, something like setTimeout will make the line execute after the API has been executed. See below incase anyone was having similar issues:
<template>
<div class="container" style="margin-top: 90px;">
<div id="vizContainer2"></div>
</div>
</template>
<script>
export default {
name: 'TableauHolder',
methods: {
getUnderlyingData(){
const containerDiv = document.getElementById("vizContainer2")
let url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms"
let options = {
hideTabs: true,
hideToolbar: true,
onFirstInteractive: () => {
}
}
this.viz = new window.tableau.Viz(containerDiv, url, options)
setTimeout(() => {
let sheet = this.viz.getWorkbook().getActiveSheet();
console.log(sheet);
}, 3000);
},
},
mounted () {
window.addEventListener('load', () => {
this.getUnderlyingData();
})
}
}
</script>

data in Vue instance doesn't get updated after axios post response

I am writing a code piece to submit the html form data on a POST REST API. Using Vue.js and axios for that.
My Vue.js code is like this -
const app = new Vue({
el: "#main-div",
data() { return {
name: 'Please enter the name',
showEdit: true,
showResponse: true,
responseText: null
}
},
methods: {
savePerson: function () {
this.showEdit = false;
axios
.post('/api/person', {
name: this.name
})
.then(function (response) {
this.responseText = response.data.name+ ' added successfully.';
console.log(response);
console.log(response.data.name+ ' added successfully.');
})
.catch(function (error) {
this.responseText = error.message;
console.log(error);
});
}
}
}
)
And html -
<div id="main-div">
<h2> Fill out the details to create a Person</h2>
<div v-if="showEdit">
<form >
<div>
Name: <input v-bind:value = 'name' type="text" v-on:focus="name= ''" />
</div>
<div>
<button v-on:click="savePerson">Save</button>
</div>
</form>
</div>
<div v-if="showResponse">
<div><p>{{ responseText }}</p></div>
<div>
<button v-on:click="showEdit = true">Add one more person</button>
</div>
</div>
This code doesn't update responseText. That I can check in Vue plugin in browser.
Any idea what is not correct in my example?
You need to use an arrow function in the callback or else the function injects its own this context:
.then((response) => {
...
})
.catch((error) => {
...
})
Or you could use async/await:
async savePerson() {
this.showEdit = false;
try {
const response = await axios.post('/api/person', {
name: this.name
})
this.responseText = response.data.name+ ' added successfully.';
} catch(error) {
this.responseText = error.message;
}
}
to bind data with the input field you need to use v-model in the HTML and try to use the arrow function in the API call.

Vue Get uploaded files url

I am using vue and element ui to upload files. But I don't know how to get upload files url (basically I want to check the file type - jpg or pdf and then do something).
<div id="app">
<el-upload action="https://jsonplaceholder.typicode.com/posts/" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<embed width="100%" :src="dialogImageUrl">
</el-dialog>
<p>file type: "{{ checkType() }}"</p>
</div>
var Main = {
data() {
return {
dialogImageUrl: '',
dialogVisible: false
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
checkType(){
var filename = this.dialogImageUrl;
return filename.split('.').pop();
}
}
}
Please Help...
I have add this try to get URL..but it doesn't work..
var filename = document.getElementsByTagName("embed")[0].src;
console.log(filename);
you can use :before-upload attribute of el-upload. please take look of changed code.
<div id="app">
<el-upload action="https://jsonplaceholder.typicode.com/posts/" **:before-upload="checkType"** list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<embed width="100%" :src="dialogImageUrl">
</el-dialog>
<p>file type: "{{ checkType() }}"</p>
</div>
var Main = {
data() {
return {
dialogImageUrl: '',
dialogVisible: false
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
**checkType(file){**
console.log(file.type);
// do your action here based on file.type
var filename = this.dialogImageUrl;
return filename.split('.').pop();
}
}
}

Vue - how to get a file to a hidden input field

I am currently previewing an image, but would also like to actually return somehow the file to my form, so that I can later submit it in the backend, but not sure how to do that?
This is my component:
<template>
<div>
<div v-if="!image">
<h2>Select an image</h2>
<input type="file" #change="onFileChange">
</div>
<div v-else>
<img :src="image" />
<button #click="removeImage">Remove image</button>
<input type="file" v-bind:value="{ file }" style="display:none">
</div>
</div>
</template>
<script>
export default {
data() {
return {
image: '',
formData:new FormData()
}
},
methods: {
onFileChange: function onFileChange(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
this.formData.append('file', files[0]);
},
createImage: function createImage(file) {
var image = new Image();
var reader = new FileReader();
var vm = this;
reader.onload = function (e) {
vm.image = e.target.result;
};
reader.readAsDataURL(file);
},
removeImage: function removeImage(e) {
this.image = '';
}
}
}
</script>
I have tried with adding formData:new FormData() to data function and then appending the file to formData object like this:
this.formData.append('file', files[0]);
But I get an error:
formData is not defined
Hi I think the error caused by v-bind:value="{ file } , you should remove it, and it will work:
<input type="file" style="display:none">
You can't use v-model = "file" to get the file data, and what you have done with this.formData.append('file', files[0]); is the right way to get the data, if you want to get the data in the scope of your components, you can do something like this:
data() {
return {
image: '',
formData:new FormData(),
file: null
}
},
methods: {
onFileChange: function onFileChange(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
this.formData.append('file', files[0]);
this.file = files[0];
}
....
reference:
https://laracasts.com/discuss/channels/vue/vuejs-using-v-model-with-input-typefile?page=1
http://codepen.io/Atinux/pen/qOvawK/