How can I pass input file with vue.js 2? - vue.js

My vue component like this :
<template>
<div class="modal" tabindex="-1" role="dialog">
...
<div class="form-group">
<label for="change-image">Change image</label>
<input type="file" name="replace" v-on:change="changeImage">
</div>
<div class="form-group">
<label for="alt-image">Alt attr</label>
<input type="text" class="form-control" v-model="altImage">
</div>
<div class="checkbox">
<label>
<input type="checkbox" v-model="mainCover"> Set Cover
</label>
</div>
<button type="button" class="btn btn-success" #click="editImageProduct">
Edit
</button>
...
</div>
</template>
<script>
export default{
...
data() { return {altImage: '', mainCover: '', imageChanged: '', image: ''}},
methods: {
editImageProduct(event) {
const payload = {alt_image: this.altImage, main_cover: this.mainCover, image_changed: this.imageChanged}
this.$store.dispatch('editImageProduct', payload)
},
changeImage(e) {
var files = e.target.files || e.dataTransfer.files
if (!files.length)
return;
this.createImage(files[0])
this.imageChanged = files[0]
},
createImage(file) {
var image = new Image()
var reader = new FileReader()
var vm = this
reader.onload = (e) => {
vm.image = e.target.result
};
reader.readAsDataURL(file)
},
}
}
</script>
I want to send the parameters to controller. It will go through modules, api, routes and controller
On the controller, I do like this :
public function editImage(Request $request)
{
dd($request->all());
}
When executed, the result like this :
array:5 [
"alt_image" => "test alt"
"main_cover" => true
"image_changed" => []
]
The param image_changed is empty
Whereas on the component, I do console.log, it display the result
When I do console.log(files[0]), the result like this :
How can I solve this problem?

Related

How to clean input in Vue.Js

im have little problem with clean input after functions complete
Can someone tell me what im do wrong
After functions is complete im try to clean the input
But i dont have any result with this
this is my code in Vue Component
<form role="form">
<div class="card-body">
<div class="form-group">
<label for="file">Upload File</label>
<div class="input-group">
<div class="custom-file">
<input
type="file"
class="custom-file-input"
id="file"
ref="file"
v-on:change="handleFileUpload"
/>
<label class="custom-file-label" for="file">Choose file</label>
</div>
</div>
</div>
</div>
<div class="card-footer">
<button v-on:click="onClickUploadAccounts" class="btn btn-primary">Upload</button>
<button v-on:click="onClickSetLoader" class="btn btn-primary">Loader</button>
</div>
</form>
methods: {
handleFileUpload(){
this.file = this.$refs.file.files[0]
},
onClickUploadAccounts(){
let formData = new FormData();
formData.append('file', this.file);
this.$store.commit('imports/setIsLoad', true)
axios.post( '/admin-account-import',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(() => {
console.log('SUCCESS!!')
this.$store.commit('imports/setIsLoad', false)
this.file = ''
formData.delete('file')
formData.append('file', this.file = '')
})
.catch(() => {
console.log('FAILURE!!');
});
},
onClickSetLoader()
{
this.$refs.file.files = ''
},
},
You need to set this.file to null. in your data
data: function () {
return {
file: null
}
}
And you can remove in your methods
this.file = ''
formData.delete('file')
formData.append('file', this.file = '')

vform multiselected dropdown default selected and expected an array error

Can anyone help me I used Vform When I clicked edit button then it's show this error that expect array but I used already array in categories[] and also how to selected default category ?
I used vform and axios. I want to make a post with multiple category it's store successfully but when I click edit button then I get error that it's expected an array but I bind it an array and also how I make default select when it's edit mode ?
<form #submit.prevent="editMode ? updateVal() : createVal()">
<div class="modal-body">
<div class="form-group">
<label>Category</label>
<select class="form-control"
multiple
v-model="form.categories"
name="categories[]"
:class="{ 'is-invalid': form.errors.has('categories') }">
<option v-for="catetoryValue in getCategory" :key="catetoryValue.id" :value="catetoryValue.id">{{ catetoryValue.name }}</option>
</select>
<has-error :form="form" field="categories"></has-error>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button v-show="editMode" type="submit" class="btn btn-primary">Update</button>
<button v-show="!editMode" type="submit" class="btn btn-primary">Create</button>
</div>
</form>
<script>
export default {
data() {
return {
editMode: false,
categories:[],
selected: null,
form: new Form({
id: "",
title: "",
categories:[],
})
};
},
methods: {
getCategory(){
if (this.$gate.isAdminOrAuthor()) {
axios
.get("api/getcategory")
.then((response) => {
this.getCategory = response.data
})
.catch(() => {
console.log("Error...");
});
}
},
newModal() {
this.editMode = false;
this.form.reset();
$("#addnewmodal").modal("show");
},
edidModal(value) {
this.editMode = true;
this.form.reset();
$("#addnewmodal").modal("show");
this.form.fill(value);
},
},
created() {
this.getCategory();
},
};
</script>

VueJs // V-for with v-modal // Data update issue after button clicked

UPDATED!!! Full component's code added:
I've inputs rendered via v-for loop. List of inputs depends on an API response. I need a "plus" and "minus" buttons to change input's value. I almost find a solution but value changes only on sibling input change but not on button click.
Here is my code...
<template>
<div class="allPlaces" id="allPlaces">
<div class="wiget__row wiget__row--top" id="topRow">
<div class="wiget__details wiget__details--allPlaces">
<div class="wiget__logo">
<img class="wiget__img wiget__img--logo" width="28" height="30" src="../../img/kassy_logo_img.png" alt="">
<img class="wiget__img wiget__img--logoTXT" width="59" height="28" src="../../img/kassy_logo_text.png" alt="">
</div>
<div class="wiget__eventDetails">
<p class="wiget__eventName">{{this.show[0].title}}</p>
<div class="wiget__place">
<span class="wiget__venue">{{this.building[0].title}}, </span>
<span class="wiget__venueHall">{{this.hall[0].title}}</span>
</div>
<div class="wiget__dateOfEvent">
<span class="wiget__time">{{this.getTime(this.event[0].date)}}</span>
<span class="wiget__date">{{this.getDate(this.event[0].date)}}</span>
</div>
</div>
</div>
</div>
<div class="allPlaces__wrapper">
<h1 class="allPlaces__title">Оформление заказа</h1>
<p class="allPlaces__description">Для оформления заказа выберите нужное количество мест</p>
<div class="allPlaces__content">
<div class="allPlaces__entrance" v-for="(entrance, index) in places.entrance" :key="entrance.id">
<div class="allPlaces__infoBlock">
<div>
<div class="allPlaces__available">
<span class="allPlaces__label allPlaces__label--places">Доступно мест:</span>
<span class="allPlaces__data">&nbsp{{entrance.vacant_places}}</span>
</div>
<div class="allPlaces__title allPlaces__title--entrance">{{getEntranceName(entrance)}}</div>
</div>
<div class="allPlaces__price">
<span class="allPlaces__label">Цена: </span>
<span class="allPlaces__data">{{entrance.price}}</span>
</div>
</div>
<div class="allPlaces__orderBlock">
<div class="allPlaces__inputBlock">
<input class="allPlaces__input" type="number" name="amount" v-bind:id="tickets"
v-model="tickets[index]" #blur="showLabel($event, index)">
<label class="allPlaces__label allPlaces__label--input"
#click="hideLabel($event, index)">Количество мест
</label>
</div>
<div class="allPlaces__btnBlock">
<button class="allPlaces__btn allPlaces__btn--minus" type="button" name="button"
#click="removeTicket(index)"></button>
<button class="allPlaces__btn allPlaces__btn--plus" type="button" name="button"
#click="addTicket(index)">
</button>
</div>
<button class="allPlaces__btn allPlaces__btn--confirm" type="button" name="button"
#click="addEntrancePlaceToCart(entrance, index)">
<img class="allPlaces__img allPlaces__img--cart" src="../../img/cartWhite.png" alt="Корзина">
<span class="allPlaces__text allPlaces__text--cart">В корзину</span>
</button>
</div>
</div>
</div>
</div>
<div class="wiget__row wiget__row--bottom" id="bottomRow">
<div class="wiget__row">
<div class="wiget__amountBlock">
<span class="wiget__tickets">
<span>Билеты:</span>
<span class="wiget__amount wiget__amount--tickets">{{this.ticketsInCart.count}}</span>
<span>шт.</span>
</span>
<div class="wiget__money">
<span class="wiget__money wiget__money--label">Итого:</span>
<p>
<span class="wiget__amount wiget__amount--money">{{this.ticketsInCart.total}}&nbsp</span>
<span class="wiget__amount wiget__amount--money">руб.</span>
</p>
</div>
</div>
<div class="wiget__btnBlock">
<button class="wiget__btn wiget__btn--goToHall" type="button" name="button"
#click="goToHall()">
Выбрать на схеме
</button>
<button class="wiget__btn wiget__btn--confirm" type="button" name="button"
#click="goToCartPage($event)">Оформить заказ</button>
</div>
</div>
<div class="wiget__row wiget__row--service">
<span class="wiget__service">Сервис предоставлен:</span>
Kassy.ru
</div>
</div>
</div>
</template>
<script>
import vueMethods from '../../mixins/methods'
import { mapState } from 'vuex'
export default {
name: 'allPlaces',
mixins: [vueMethods],
data () {
return {
tickets: []
}
},
mounted () {
this.$nextTick(function () {
window.addEventListener('resize', this.updateAllPlacesOnResize)
this.setupAllPlaces()
})
},
methods: {
setupAllPlaces () {
let allPlaces = document.getElementById('allPlaces')
let topRow = document.querySelector('.wiget__row--top')
let wrapper = document.querySelector('.allPlaces__wrapper')
let bottomRow = document.querySelector('.wiget__row--bottom')
let allPlacesHeight = allPlaces.clientHeight
let topRowHeight = topRow.clientHeight
let bottomRowHeight = bottomRow.clientHeight
let wrapperHeight = allPlacesHeight - topRowHeight - bottomRowHeight
console.log('topRowHeight ', topRowHeight)
console.log('allPlacesHeight ', allPlacesHeight)
console.log('bottomRowHeight ', bottomRowHeight)
console.log('wrapperHeight ', wrapperHeight)
wrapper.style.minHeight = wrapperHeight + 'px'
},
updateAllPlacesOnResize (event) {
this.setupAllPlaces()
},
getEntranceName (entrance) {
let sectionId = entrance.section_id
let section = this.section
let sectionName = section.filter(function (e) {
return e.id === sectionId
})
return sectionName[0].title
},
addTicket (index) {
console.log(this.tickets)
console.log(this.tickets[index])
this.tickets[index] = parseInt(this.tickets[index]) + 1
return this.tickets
},
removeTicket (index) {
this.tickets[index] = parseInt(this.tickets[index]) - 1
},
addEntrancePlaceToCart (entrance, index) {
console.log('entrance.id to add to cart ', entrance.id)
let db = this.db
let places = parseInt(this.tickets[index])
console.log('places ', places)
console.log('index ', index)
let sessionId = this.sessionId
let entranceId = parseInt(entrance.id)
let params = {db, places, sessionId, entranceId}
this.$store.dispatch('addEntrancePlaceToCart', params) // Добавили место в корзину
},
goToHall () {
this.$store.dispatch('closeAllPlaces')
this.$store.dispatch('openHallPlan')
},
hideLabel (e, index) {
console.log('CLICKED')
console.log('index click', index)
let input = document.getElementsByClassName('allPlaces__input')
let target = e.target
input[index].focus()
console.log('this.tickets ', this.tickets)
console.log(target)
if (this.tickets === '') {
target.style.display = 'block'
} else {
target.style.display = 'none'
}
},
showLabel (e, index) {
console.log('BLUR')
console.log('index blur', index)
let label = document.getElementsByClassName('allPlaces__label allPlaces__label--input')
console.log(this.tickets[index])
if (this.tickets[index] === '' || this.tickets[index] === undefined) {
label[index].style.display = 'block'
} else {
label[index].style.display = 'none'
}
}
},
destroyed () {
window.removeEventListener('resize', this.setupAllPlaces)
},
computed: {
...mapState({
db: state => state.onload.currentDb,
currentEvent: state => state.onload.currentEvent,
modals: state => state.modals,
metric: state => state.onload.eventData.metric,
section: state => state.onload.eventData.section,
show: state => state.onload.eventData.show,
event: state => state.onload.eventData.event,
building: state => state.onload.eventData.building,
hall: state => state.onload.eventData.hall,
places: state => state.onload.eventData.places,
placesSeated: state => state.onload.eventData.places.place,
sessionId: state => state.cart.sessionId,
ticketsInCart: state => state.cart.ticketsInCart
})
}
}
</script>
<style scoped lang="stylus">
#import '../../styles/Root/allPlaces'
#import '../../styles/Root/wiget'
</style>
Please advise
You tickets is not correctly initialized. The data populated a empty array but the template will add new element without using the VueJs way of adding reactivity.
What happen is similare to:
let tickets = [];
tickets[0] = ...;
In VueJs you should use push to insert an element to an array and not using the "sparse implementation".
So when your places is being populated inside your store you should create the tickets table from the size of it. Something similare to the following in a watcher or elsewhere depending on your need:
this.tickets = this.place.map(_ => 0);

Upload image from local storage using Vuejs

When you click on "Choose file" and select an image for upload, the path however appears. The image gets uploaded only after you click "Choose file" one more time.
How to resolve this and upload as and when the file is chosen?
Any help would be much appreciated. Thank you.
new Vue({
el: '.app',
data: {
userImage: ''
},
methods: {
onFileChange(e) {
var files = e.target.files || e.dataTransfer.files
if (!files.length) {
return
}
this.createImage(files[0])
},
createImage(file) {
var reader = new FileReader()
var vm = this
reader.onload = (e) => {
vm.userImage = e.target.result
}
reader.readAsDataURL(file)
},
removeImage: function (e) {
this.userImage = ''
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div class="col-xl-3 col-lg-3 col-md-4 col-sm-6 col-xs-6 text-center app">
<img class="profile-image" :src="userImage" />
<div v-if="!userImage">
<input type="file" round class="change-profile-image" #change="onFileChange" />
</div>
<div v-else>
<button class="delete-profile-image" color="secondary" icon="delete" #click="removeImage">Delete</button>
</div>
</div>
My code on JSfiddle.
You shouldn't rely on listening to the click event. What you are looking for is the change event instead, i.e. use #change instead of #click:
<input type="file" round class="change-profile-image" #change="onFileChange" />
See updated fiddle: https://jsfiddle.net/hrtzezk8/5/, or the proof-of-concept snippet below:
new Vue({
el: '.app',
data: {
userImage: ''
},
methods: {
onFileChange(e) {
var files = e.target.files || e.dataTransfer.files
if (!files.length) {
return
}
this.createImage(files[0])
},
createImage(file) {
var reader = new FileReader()
var vm = this
reader.onload = (e) => {
vm.userImage = e.target.result
}
reader.readAsDataURL(file)
},
removeImage: function (e) {
this.userImage = ''
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div class="col-xl-3 col-lg-3 col-md-4 col-sm-6 col-xs-6 text-center app">
<img class="profile-image" :src="userImage" />
<div v-if="!userImage">
<input type="file" round class="change-profile-image" #change="onFileChange" />
</div>
<div v-else>
<button class="delete-profile-image" color="secondary" icon="delete" #click="removeImage">Delete</button>
</div>
</div>

Click-to-Edit text field with Vue

I am working on Vue js and having an issue editing a field. When I click on a field to edit it, all the editable fields become active. Here is my code.
export default {
props: ['profileHeight'],
data() {
return {
User: User,
isEditing: false,
form:{
name:'',
email: '',
},
};
},
mounted() {
},
methods: {
activateInEditMode() {
this.isEditing = true
},
deActivateInEditMode() {
this.isEditing = false
}
}
}
<span>Profile settings</span>
<p>Full name<span v-on:click="activateInEditMode" v-show="!isEditing">{{User.state.auth.name}}</span>
<span v-show="isEditing" >
<input v-model="form.name" type="text" class="form-control" >
</span>
</p>
<p>E-mail<span>{{User.state.auth.email}}</span>
<span v-show="isEditing" >
<input v-model="form.email" type="text" class="form-control" >
</span>
</p>
Try using focus and blur methods to show/hide form elements!
Hope this helps!
new Vue({
el: '#app',
data(){
return {
user : {
name: '',
email: ''
},
editField : ''
}
},
methods : {
focusField(name){
this.editField = name;
},
blurField(){
this.editField = '';
},
showField(name){
return (this.user[name] == '' || this.editField == name)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<h1>Profile settings</h1>
<label for="user-name">Full name</label>
<div class="field">
<span class="field-value" v-show="!showField('name')" #click="focusField('name')">{{user.name}}</span>
<input v-model="user.name" v-show="showField('name')" id="user-name" type="text" class="field-value form-control" #focus="focusField('name')" #blur="blurField">
</div>
<label for="user-email">Email address</label>
<div class="field">
<span class="field-value" v-show="!showField('email')" #click="focusField('email')">{{user.email}}</span>
<input v-model="user.email" v-show="showField('email')" type="email" class="field-value form-control" #focus="focusField('email')" #blur="blurField">
</div>
</div>
There are are dozens of ways to do this. I might recommend a component.
console.clear()
Vue.component("editable",{
props:["label", "value"],
template:`
<p>
{{label}}
<span #click="editing=true" v-show="!editing">
{{value}}
</span>
<span v-show="editing" >
<input :value="value"
#input="$emit('input', $event.target.value)"
#keydown.enter="editing=false"
type="text"
class="form-control" >
</span>
</p>
`,
data(){
return {
editing: false,
}
}
})
const User = {
name: 'bob',
email: 'bob#example.com'
}
new Vue({
el:"#app",
data() {
return {
form: User
};
},
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<span>Profile settings</span>
<editable label="Full name" v-model="form.name"></editable>
<editable label="E-mail" v-model="form.email"></editable>
<br>
{{form}}
</div>
I have written a component for this, I call it Click-to-Edit.
What it does:
Supports v-model
Saves changes on clicking elsewhere and on pressing Enter
ClickToEdit.vue:
<template>
<div>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
#keyup.enter.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
v-focus=""
/>
<p v-else="" #click="edit = true;">
{{valueLocal}}
</p>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>