I'm working on a VueJS Application and I'm using net core as backend,
I have a component with an upload function that is working but not as expected, for example, if i chose to upload 3 files it would upload just the first out of 3.
My HTML
<div class="container">
<div class="large-12 medium-12 small-12 cell">
<label>
Files
<input type="file" name="file" ref="files" multiple v-on:change="fileChange($event.target.files)" />
</label>
<v-btn outline color="primary" dark v-on:click="upload()">Submit</v-btn>
</div>
</div>
Part of my script
export default {
name: 'Profile',
data() {
return {
records: [],
application: [],
profile: [],
history: [],
userValues: [],
dialog: false,
notifications: false,
sound: true,
widgets: false,
files: new FormData()
};
},
methods: {
});
}
And my Controller
[Produces("application/json")]
[Route("api/[controller]")]
public class UploadController : Controller
{
private IHostingEnvironment _hostingEnvironment;
public UploadController(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
{
file.CopyTo(stream);
}
}
return Json("Upload Successful.");
}
catch (System.Exception ex)
{
return Json("Upload Failed: " + ex.Message);
}
}
}
Also along with the files, I would like to pass email: this.profile.email as a parameter from my vue.
Like I said it is working but just one file at the time.
var file = Request.Form.Files[0]; That will pop off only the first file from your request. Instead, you need to check for
Instead access your files in a loop:
foreach(uploadedFile in Request.Form.Files) {
}
Related
I am trying to make some API calls via MsGraph from Chrome-extension.I am using Vue2 to build this extension and 'vue-msal'. When I print msal object it gets in this format:
But when I call it I get nothing.It suppose to open a logIn window.
<div id="demo">
<div v-if="user">
<div>Welcome {{user.name}}</div>
<div v-if="user.profile.jobTitle">Your job title is {{user.profile.jobTitle}}</div>
<div><button #click="signOut()">logout</button></div>
</div>
<div v-else>
<button #click="signIn()"> Please sign-in</button>
</div>
</div>
</template>
<script>
import { msalMixin } from 'vue-msal';
export default {
mixins: [msalMixin],
name: 'HelloWorld',
mounted () {
},
computed: {
user() {
let user = null;
if (this.msal.isAuthenticated) { // Note that the dollar sign ($) is missing from this.msal
user = {
...this.msal.user,
profile: {}
}
if (this.msal.graph && this.msal.graph.profile) {
user.profile = this.msal.graph.profile
}
}
return user;
}
},
methods:{
async signIn(){
console.log(this.$msal,'msal')
console.log(this.$msal.signIn(),'signIn func')
},
signOut(){
this.$msal.signOut()
}
}
}
</script>
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"
/>
I am new to Vuejs and come across this bug which I have no idea what I have done wrong. I am not receiving any console errors. It doesn't work on initial page load but it seems to work after I comment something out (or make a minor change). It will still then continue to work if I reverse the changes I just made and put it back to the original code. But once again on a fresh page load it won't work.
The issue: I am making a to do list and on page load when I add new tasks through the input field, the list does not appear on the page like it should be. I also console log the data array for this and it shows it is getting added to the array but is not getting rendered to the page. No console errors. In my code I will comment out some other data property (there are 2 additional ones below todosList in the TodoList.vue file that are currently not being used yet) and save and then the tasks will automatically appear on the page. So I think oh ok that might be the issue so with this new minor change I decide to refresh the page to see if it works as expected. Nope it doesn't so I then uncomment out what I previously commented out and save and the list appears again. But once again if I refresh the page it doesn't work. It only seems to be if I make a change inside the data function in the TodoList.vue file.
Additional info: The data is stored in the parent todos[] (App.vue), updated/pushed to array in a child (TodoCreate.vue) and sent back to the parent using $emit. This data is then sent through to another child (TodoList.vue) using props so that it can be rendered on the page.
Wondering if there is something that is not quite right in my code which is causing this to bug out like that. I will include everything in case it is something that looks unrelated to me but could be causing it.
Here is also a link to a code sandbox where the issue can be replicated by following the instructions on the page https://codesandbox.io/s/adding-new-todo-not-working-properly-jwwex?file=/src/components/TodoList.vue
main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
App.vue
<template>
<div :class="currentMode">
<the-header #modeToggled="updateMode($event)"></the-header>
<main>
<todo-create #addedTodos="updateTodos"></todo-create>
<todo-list :todos="todos"></todo-list>
</main>
</div>
</template>
<script>
import TheHeader from './components/TheHeader.vue';
import TodoCreate from './components/TodoCreate.vue';
import TodoList from './components/TodoList.vue';
export default {
name: 'App',
components: {
TheHeader,
TodoCreate,
TodoList,
},
data() {
return {
currentMode: {
dark_mode: true,
light_mode: false
},
todos: [],
}
},
methods: {
updateMode(mode) {
this.currentMode = mode;
},
updateTodos(data) {
this.todos = data;
console.log(this.todos);
},
toggleCompleted() {
}
},
// provide() {
// return {
// todos: this.todos,
// };
// }
}
</script>
TheHeader.vue
<template>
<h1>To-do App</h1>
<div>
<label for="toggle-mode" aria-label="Toggle light and dark mode"></label>
<input type="checkbox" id="toggle-mode" #change="toggleMode">
</div>
</template>
<script>
export default {
emits: ['modeToggled'],
data() {
return {
toggleState: false,
}
},
methods: {
toggleMode() {
this.toggleState = !this.toggleState;
this.$emit('modeToggled', this.modeClasses);
}
},
computed: {
modeClasses() {
return {
dark_mode: !this.toggleState,
light_mode: this.toggleState
}
}
}
}
</script>
TodoCreate.vue
<template>
<div>
<label for="newtodo" class="sr-only">Create new to do</label>
<input type="text" id="newtodo" placeholder="Create a new todo..." v-model="todoval" v-on:keyup.enter="addTodo" >
</div>
</template>
<script>
export default {
emits: ['addedTodos'],
data() {
return {
todoval: '',
taskNumber: 0,
todos: [],
};
},
methods: {
addTodo() {
const val = this.todoval;
const taskNumber = this.taskNumber;
this.todos.push({ taskID: taskNumber, value: val, complete : 'not-completed'});
this.todoval = '';
this.taskNumber++;
console.log(this.todos);
this.$emit('addedTodos', this.todos);
},
}
}
</script>
TodoList.vue
<template>
<ul class="todo-items" :class="filterClass">
<li class="drop-zone" v-for="(listItem, index) in todosList" :class="listItem.complete" :key="listItem.taskID"
#drop='onDrop($event, index)'
#dragover.prevent
#dragenter.prevent>
<div class="drag-el" draggable="true"
#dragstart='startDrag($event, index)'>
<label :for="'checkbox-'+index" :aria-label="'Mark task ' + listItem.value + ' as completed'"></label>
<input type="checkbox" :id="'checkbox-'+index" #change="toggleCompleted(index, listItem.value, listItem.complete, listItem.taskID)">
<input type="text" disabled :value="listItem.value">
<img src="../assets/icon-cross.svg" #click="removeTask(index)">
</div>
</li>
</ul>
</template>
<script>
export default {
props: {
todos: Object,
filterClass: String
},
// inject: ['todos'],
data() {
return {
todosList: this.todos,
// completedTodos: [],
// activeTodos: [],
};
},
// watch: {
// todosList(data) {
// data.filter(function(todo) {
// if(todo.completed == 'completed') {
// completedTodos.push(todos);
// }
// });
// }
// },
methods: {
startDrag: (evt, item) => {
evt.dataTransfer.dropEffect = 'move'
evt.dataTransfer.effectAllowed = 'move'
evt.dataTransfer.setData('itemID', item)
},
onDrop (evt, list) {
const itemID = evt.dataTransfer.getData('itemID');
const movedData = this.todosList[itemID];
this.todosList.splice(itemID,1);
this.todosList.splice(list,0, movedData);
},
toggleCompleted() {
// still need to write this method
},
removeTask() {
// still need to write this method
}
}
}
</script>
On my website you can upload a dog with attributes and images.
Vuejs is the frontend and Laravel the backend.
I am using this vue-dropzone component in my project to upload images.
The problem
I want to upload the images and the attributes of a dog at the same time (when the user clicks the submit button), so that the image files can be linked to the dog's id in the database.
Laravel function to register a new dog (route: 'api/dogs')
public function store(Request $request)
{
$attributes = [
'name' => $request->input('name'),
'type' => $request->input('dogType'),
...
];
$dogId = Dog::insertGetId($attributes);
// Upload files
if ($request->hasFile('files')) {
// getting all files
$files = $request->file('files');
// Count files to be uploaded
$file_count = count($files);
// start count how many uploaded
$uploadcount = 0;
if($uploadcount == $file_count) {
return true;
} else {
FileController::store($request, 0, 0, $dogId, $files, $uploadcount);
}
}
return $dogId;
}
Dropzone component (Formdropzone)
<template>
<div>
<dropzone
:id="this.id"
:url="this.url"
:accepted-file-types='"image/*"'
:use-font-awesome="true"
:preview-template="template"
:auto-process-queue="false" <----
:upload-multiple="true"
:parallel-uploads=100
:max-files=100
#vdropzone-success="showSuccess"
>
</dropzone>
</div>
</template>
<script>
import Dropzone from 'vue2-dropzone'
export default {
props: {
id: {
type: String,
required: true
},
url: {
type: String,
required: true
}
},
components: {
Dropzone
},
methods: {
showSuccess(file) {
console.log('A file was successfully uploaded')
},
template() {
return `
<div class="dz-preview dz-file-preview">
<div class="dz-image" style="width: 200px;height: 200px">
<img data-dz-thumbnail /></div>
<div class="dz-details">
<div class="dz-size"><span data-dz-size></span></div>
<div class="dz-filename"><span data-dz-name></span></div>
</div>
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
<div class="dz-error-message"><span data-dz-errormessage></span></div>
<div class="dz-success-mark"><i class="fa fa-check"></i></div>
<div class="dz-error-mark"><i class="fa fa-close"></i></div>
</div>
`;
}
}
}
</script>
Register dog component
<tab-content title="Images">
<div class="form__input__wrapper">
<span class="label">Images (optional)</span>
<formdropzone url="http://domain.local/api/dogs" ref="dogDropzone" id="dogDropzone"></formdropzone>
</div>
</tab-content>
<script>
import Formdropzone from './Formdropzone'
export default {
data() {
return {
dog:{
name: '',
dogType: '',
...
}
}
},
methods: {
publish() {
this.$http.post('api/dogs', this.dog)
.then(response => {
this.$refs.dogDropzone.processQueue() <----
this.$router.push('/feed')
})
}
},
components: {
'formdropzone': Formdropzone
}
</script>
The error message
Uncaught (in promise) TypeError: Cannot read property 'processQueue' of undefined
I would be very thankful for any kind of help!
Can someone help me on how to upload a file on pouchdb and display those uploaded files on page. I want to upload a file including name info of that file. When I check the fetch files using the console I can see [object object]. Am I doing the right thing? Any advice is well appreciated. Here is my code.
//Notes.vue
// By the way Im using onsen ui for this
<template>
<v-ons-page>
<v-ons-list>
<v-ons-list-header>Auditing</v-ons-list-header>
<v-ons-list-item v-for="note in notes">
<div class="left">
<img src="" alt="">
</div>
<div class="center">
<span>{{ note._attachment['files'].data }} File here</span>
</div>
</v-ons-list-item>
</v-ons-list>
// Customize form for uploading file and info
<v-ons-alert-dialog
modifier="rowfooter"
:visible.sync="dialogVisible"
>
<span slot="title">Create a Note</span>
//File name of the file
<v-ons-input float
placeholder="Name of note"
v-model="name"
>
</v-ons-input>
// File
<v-ons-input type="file" #change="onFileChange"></v-ons-input>
<v-ons-button #click="addNotes(name)">Submit</v-ons-button>
</v-ons-alert-dialog>
</v-ons-page>
</template>
//Here the methods for uploading and reading file uploaded
<script>
import PouchDB from 'pouchdb'
var db = new PouchDB('reviewerdb')
export default {
data() {
return {
dialogVisible: false,
notes: [],
file: '',
name: '',
path
}
},
mounted() {
this.getNotes();
print('notes: ' + this.notes);
},
//Methods just adding a desciption
methods: {
onFileChange(event) {
this.file = event.target.files[0];
},
addNotes() {
db.put({
_id: 'notes',
_attachments: {
"file": {
type: this.file.type,
data: this.file
}
}
})
},
getNotes() {
db.get('notes', {attachments:true}).then(function (note) {
this.notes = note;
});
}
}
}