Axios call on select/enter with Vue Multiselect - javascript

I have a functioning Vue Multiselect where I'm using an axios call to fill the options from my database values. This works perfectly and allows me to choose from existing options or enter new options in order to create tags.
As it is, this works perfectly. But I need a way, if possible, to make another Axios call every time the user selects and option or hits the enter key to save a tag option. Is there a way to do this?
This is my first experience with Vue and I'm really not sure how feasible this is, but basically I'm just wondering how to make an axios call every time a tag is selected or entered with the enter key
<div id="tagApp">
<multiselect
label="tag_data"
track-by="campaign_tag_id"
v-model="value"
:options="options"
:multiple="true"
:taggable="true"
#tag="addTag"
#search-change="val => read(val)"
:preselect-first="false"
:close-on-select="false"
:clear-on-select="true"
:preserve-search="true"
tag-placeholder="Add this as new tag"
placeholder="Search or add a tag"
></multiselect>
</div>
new Vue({
components: {
Multiselect: window.VueMultiselect.default
},
el: "#tagApp",
data() {
return{
value: [],
loading: false,
options: []
}
},
methods: {
read: function(val){
//console.log('searched for', val);
if (val) {
this.loading = true;
this.options = [];
const self = this;
console.log(val);
axios.get('campaigns/search',{params: {query: val}})
.then(function (response) {
self.options = response.data;
console.log(response.data);
});
} else {
this.options = [];
}
},
addTag(newTag) {
const tag = {
tag_data: newTag,
};
this.options.push(tag);
this.value.push(tag);
}
}
})

Monitor #select event and trigger a function where your Axios call will happen.
<div id="tagApp">
<multiselect
...
#select= "callAxios"
...
></multiselect>
</div>
...
methods: {
callAxios: function(val){
//your Axios call here
},
...
}
...

Related

Dropdowndown list options changes if a button is clicked ( VueJS & Laravel 6)

I want to make my dropdown list options changes when I click a button in my form.
I have a form with 3 buttons (Accounting, Department & Cashier)
I want my Transaction dropdown list to change options depending on what department has been chosen.
I already have this JSON array for each department:
What I want is when I click a button, the option will change too in my transaction dropdown.
For example, if I click registrar, only the registrar options will be available on the dropdown.
For now, this is my vue script for pulling the arrays for options:
<script>
const app = new Vue({
el:'#transactions',
data:{
trans:{}
},
mounted(){
this.getTrans();
},
methods:{
getTrans(){
axios.get('http://localhost/dqrs/api/transactions')
.then((response)=>{
this.trans=response.data
console.log(this.trans.acc);
})
.catch(function (error){
console.log(error);
});
}
}
})
</script>
And I just want to ask too if this is right for pulling my values for transaction:
The whole code should be like this:
Don't need to call getTrans() function on mounted.
Make template.
Define button click function
<script>
const app = new Vue({
el:'#transactions',
data:{
trans:{},
options: []
},
mounted(){
axios.get('http://localhost/dqrs/api/transactions')
.then((response)=>{
this.trans=response.data;
this.options = this.trans.cas;
})
.catch(function (error){
console.log(error);
});
},
methods:{
btnClick: function(category) {
if (category == 'cash') {
this.options = this.trans.cas;
} else if (category == 'account') {
this.options = this.trans.acc;
} else {
this.options = this.trans.reg;
}
}
})
</script>
<template>
<div>
<div class="d-flex">
<button v-on:click="btnClick('cash')"></button>
<button v-on:click="btnClick('account')"></button>
<button v-on:click="btnClick('register')"></button>
</div>
<select v-for="option in options" :key="option.id">
<option disabled selected>Choose Transaction...</option>
<option value="option.val">{{option.name}}</option>
</select>
</div>
</template>

How to fix input dynamic category select dropdown with ajax/json in vuejs

I'm developing a category selection template with pass in the previous selection.
But the select Only works on "on first loading" if I change the select so I get behavior error. (this unselect the parent)
I need a "light".
This is the link of project
https://zimeonline.com.br
I try changer the object vue data() in each ajax in my components
<template>
<div>
<select #change="category()" v-model="selectedId" v-bind:key="option[0].id" v-for="option in options" class="browser-default custom-select">
<option v-bind:value="op.id" v-bind:selected="op.selected==1" v-bind:key="op.id" v-for="op in option">{{op.name}}</option>
</select>
</div>
</template>
<script>
export default {
name: "ProductFormCategory",
data() {
return {
options: {},
selectedId:''
}
},
created() {
let vm = this;
vm.category();
},
methods: {
async category() {
let vm = this;
await vm.$http.get('category/'+vm.selectedId).then(function (response) {
vm.options = response.data;
}).catch(function () {
});
vm.$forceUpdate();
},
}
}
</script>
<style scoped>
.browser-default{
margin-bottom: 10px !important;
}
</style>
this URL list ALL FATHER categorys
https://api.zimeonline.com.br/api/category
this URL list ALL CHILDREN categorys
https://api.zimeonline.com.br/api/category/some_id(from father category)
exemple: https://api.zimeonline.com.br/api/category/5
Then 5 is ID from https://api.zimeonline.com.br/api/category
here an exemple of the atual code select
https://zimeonline.com.br (a litle slow in the fist time)
I'm not sure that I understand your questions. But I see some problems in your code:
Why did you put a v-for in both select and option?
In the first loop, you bind a key to option[0] instead of options[0] or option
Also a tip: You could use vm.$set to make reactive variables
Solution for category basead from parent id with select input option sub-menu
<script>
export default {
name: "ProductFormCategory",
props:{
setCategoryId:String
},
data() {
return {
options: {},
categoryId: ''
}
},
created() {
let vm = this;
vm.categoryId = vm.setCategoryId || ('');
vm.category();
},
methods: {
async category(event) {
let vm = this;
if (event) {
vm.categoryId = (event.target.value);
}
await vm.$http.get('category/' + vm.categoryId).then(function (response) {
vm.options = response.data;
}).catch(function () {
});
},
}
}
<template>
<div>
<select
#change="category($event)"
v-bind:key="option[0].id"
v-for="option in options"
class="browser-default custom-select">
<option value="">Selecione uma categoria</option>
<option
v-bind:value="op.id"
v-bind:selected="op.selected==1"
v-bind:key="op.id"
v-for="op in option">
{{op.name}}
</option>
</select>
</div>

Vue multiselect not adding new tags

I'm using a Vue Multiselect instance with 2 functions (one basically hits the database for an autocomplete function, which works. The other is adding a new one that isn't in the database)
So say 'Tag One' is in the database, if I type that and it shows then hitting enter or selecting will save it to the tags (multiselect with tagging enabled). However, if I type 'Tag Three' which isn't in the database and I hit enter or select, it just disappears and doesn't add to the tags or call the axios function in my addTag method.
What exactly am I doing wrong?
<script src="https://unpkg.com/vue-multiselect#2.1.0"></script>
<script src="https://unpkg.com/#johmun/vue-tags-input/dist/vue-tags-input.js"></script>
<div id="tagApp">
<multiselect
label="tag_data"
track-by="campaign_tag_id"
v-model="value"
:options="options"
:multiple="true"
:taggable="true"
#tag="addTag"
#search-change="val => read(val)"
:preselect-first="false"
:close-on-select="false"
:clear-on-select="true"
:preserve-search="true"
tag-placeholder="Add this as new tag"
placeholder="Search or add a tag"
></multiselect>
</div>
new Vue({
components: {
Multiselect: window.VueMultiselect.default
},
el: "#tagApp",
data() {
return{
value: [],
loading: false,
options: []
}
},
methods: {
read: function(val){
if (val) {
this.loading = true;
this.options = [];
const self = this;
console.log(val);
axios.get('search',{params: {query: val}})
.then(function (response) {
self.options = response.data;
console.log(response.data);
});
} else {
this.options = [];
}
},
addTag(newTag) {
const tag = {
tag_data: newTag,
};
const campaign_id = document.querySelector("input[name=campaign_id]").value;
this.options.push(tag);
this.value.push(tag);
axios.post('tags/save',{
tag_data: newTag,
})
.then(function (response){
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
})
I don’t think you are doing anything wrong, I just don’t think the component supports what you want to do.
But, what you could do is always add the search term to the options array if it isn’t there already. Putting the below in the axios callback could be all you need.
self.options = response.data;
self.options.push(val)
Now you could slice it to the front, or keep it pushed at the end, and code to prevent duplicates etc.

Vee Validate field validation not updating

I have created a settings page where users can update their email addresses. Everything worked fine but suddenly the validation is not updating anymore. Only the first change of the input field triggers validateState().
Any further changes will not trigger this function so the status of that field stays as it is.
I have compared the code with other components that use the same code and they still work fine.
I am using bootstrap-vue components for the form.
<template>
<div class="row">
<div class="col-md-12">
<b-form #submit="onSubmit">
<b-form-group :label="$t('general.email')"
label-for="settingsEmail"
:invalid-feedback="errors.first('email')">
<b-form-input id="settingsEmail"
type="text"
v-model="form.email"
:disabled="saving"
name="email"
:state="validateState('email')"
v-validate="{required: true, email: true}">
</b-form-input>
</b-form-group>
<b-button type="submit" variant="primary" :disabled="saving || !hasChanged() || errors.any()"><i class="fa fa-refresh fa-spin fa-fw" v-if="saving"></i> {{$t('general.save')}}</b-button>
</b-form>
</div>
</div>
</template>
<script>
import {UPDATE_USER} from '../config/actions'
export default {
name: 'settingsAccount',
data() {
return {
form: {},
saving: false
}
},
computed: {
user: function() {
return this.$store.getters.getUser;
}
},
created() {
this.init();
},
methods: {
init() {
this.form.email = this.user.email;
},
hasChanged() {
if(this.form.email !== this.user.email) {
return true;
}
return false;
},
onSubmit(event) {
event.preventDefault();
this.saving = true;
this.$validator.validateAll().then((result) => {
if (result) {
let data = {};
if(this.form.email !== this.user.email) {
data.email = this.form.email;
}
this.$store.dispatch(UPDATE_USER, data).then(() => {
this.saving = false;
this.$validator.reset();
}).catch(() => {
this.saving = false;
});
} else {
this.saving = false;
}
});
},
validateState(ref) {
if (this.veeFields[ref] && (this.veeFields[ref].dirty || this.veeFields[ref].validated)) {
return !this.errors.has(ref)
}
return null
},
}
}
</script>
The problem you're having is that the form data element is an empty object, so it will only trigger reactivity when the whole object changes. Either you need to change your data to be this:
data() {
return {
form: {email:''},
saving: false
}
},
Or in your init function, explicitly add the email property as reactive:
methods: {
init() {
this.$set(form,'email',this.user.email)
},
//...
If you're not clear on why, you can read the details here: https://v2.vuejs.org/v2/guide/reactivity.html
A working example (minus vuex) here: https://codesandbox.io/s/x4kp93w3o
PS, when writing questions about vue, it's very helpful to boil it down to a simpler example. Get rid of vuex, remove your translation stuff. Sometimes the answer will jump out at you once you have it as simple as possible.

File Upload Error in VuesJS Form and Rails 5.1

I have a form that is built with Vuejs in my Rails 5.1 app. All my fields work well and persist data to the database, except for file uploads. I get the error
[Vue warn]: Error compiling template: printed at the top of the console, then essentially my entire template code, then
- <input v-model="variation.photo_one" type="file">:
File inputs are read only. Use a v-on:change listener instead.
I am new to Vuejs and cannot figure out how to get this to work even after reading many other online posts regarding this.
_form.html.erb
<%= content_tag :div,
id: "product-form",
data: {
id: product.id,
product: product.to_json(except: [:id, :created_at, :updated_at]),
variations_attributes: product.variations.to_json(except: [:product_id, :created_at, :updated_at]),
} do %>
...
<div class="col-md-4 upload-block">
<label>Photo One</label>
<input type="file" v-model="variation.photo_one" style="margin-bottom: .5em">
</div>
...
<% end %>
app_vue.js
import Vue from 'vue/dist/vue.esm'
import TurbolinksAdapter from 'vue-turbolinks'
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.use(TurbolinksAdapter)
document.addEventListener('turbolinks:load', () => {
Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
var element = document.getElementById("product-form")
if (element != null) {
var id = element.dataset.id
var product = JSON.parse(element.dataset.product)
var variations_attributes = JSON.parse(element.dataset.variationsAttributes)
variations_attributes.forEach(function(variation) { variation._destroy = null })
product.variations_attributes = variations_attributes
var app = new Vue({
el: element,
data: function() {
return { id: id, product: product }
},
methods: {
addVariation: function() {
this.product.variations_attributes.push({
id: null,
name: "",
photo_one: "",
//position: "",
_destroy: null
})
},
removeVariation: function(index) {
var variation = this.product.variations_attributes[index]
if (variation.id == null) {
this.product.variations_attributes.splice(index, 1)
} else {
this.product.variations_attributes[index]._destroy = "1"
}
},
undoRemove: function(index) {
this.product.variations_attributes[index]._destroy = null
},
saveProduct: function() {
// Create a new product
if (this.id == null) {
this.$http.post('/products', { product: this.product }).then(response => {
Turbolinks.visit(`/products/${response.body.id}`)
}, response => {
console.log(response)
})
// Edit an existing product
} else {
this.$http.put(`/products/${this.id}`, { product: this.product }).then(response => {
Turbolinks.visit(`/products/${response.body.id}`)
}, response => {
console.log(response)
})
}
},
existingProduct: function() {
return this.product.id != null
}
}
})
}
})
Files are a bit awkward in Vue. As the message says, you cannot use v-model for an input with type="file". Instead you must use the change event and call a method in your component to manually handle the file.
<input type="file" #change="handleFileChange" />
methods: {
handleFileChange(event) {
//you can access the file in using event.target.files[0]
this.fileField = event.target.files[0];
}
}
When you submit the AJAX request, you will likely need to submit a FormData object instead of submitting a javascript object. The MDN docs have an explanation on how to use that. I find the FormData is the more awkward part of dealing with file uploads. https://developer.mozilla.org/en-US/docs/Web/API/FormData

Categories

Resources