How to call api when change value in vue multiselect - javascript

How to call api when there is a change value event in vue multiselect?
i want change value in multiselect , call api and show in console. The following is my code.
<template>
<div>
<multiselect v-model="value" placeholder="Select Your Currency" label="title" track-by="title" :options="options" :option-height="10" :show-labels="false">
<template slot="singleLabel" slot-scope="props"><img class="option__image" :src="props.option.img" alt="No Man’s Sky"><span class="option__desc"><span class="option__title">{{ props.option.title }}</span></span></template>
<template slot="option" slot-scope="props"><img class="option__image" :src="props.option.img" alt="No Man’s Sky">
<div class="option__desc"><span class="option__title" :id="props.option.id">{{ props.option.title }}</span><span class="option__small">{{ props.option.desc }}</span></div>
</template>
</multiselect>
</div>
</template>
<script>
import Vue from 'vue';
import Multiselect from 'vue-multiselect'
Vue.component('multiselect', Multiselect);
export default {
props: ['options'],
components: {
Multiselect
},
data () {
return {
value: { title: 'Bitcoin', img: 'https://coinnik.com/uploads/crypto-
logos/06fa2ab3d5a0f1d60e7d236aeccd6c6a.png' },
}
},
methods: {
}
}
</script>
app.js
methods: {
stepChanged(step) {
this.currentstep = step;
},
apiCalc(){
let self = this;
axios.get('/ajax-calculation?includes=direction,direction.receiveCurrency&send_currency=2').then((response) => {
self.calcApi = response.data;
console.log('api:',self.calcApi.currency_id);
// self.calcApi.currency_id;
})
}
},
components:{
'multiselect': Multiselect
},
created() {
this.apiCalc();
},
});
html
<div class="col-md-12 mb-2">
<multiselect :options="[ { title: 'Tether', img: 'https://coinnik.com/uploads/crypto-logos/006fe133d48ea7cd45cf8ccb8cb7ec42.png' },
{ title: 'value', img: 'https://coinnik.com/uploads/crypto-logos/006fe133d48ea7cd45cf8ccb8cb7ec42.png' }]">
</multiselect>
</div>
How to define a method that I use when changing item then call api and show inside the console?

You can use the deep watch on the value variable.
watch: {
'value': {
handler: function (after, before) {
this.apiCalc();
},
deep: true
},
},

Ok, so first, you can use the #input event to recognize when something has been picked, like so:
<multiselect v-model="value" :options="options" #input="doApi" multiple></multiselect>
Then in doApi, you can check the current value.
doApi() {
console.log(this.value);
}
The value of this.value will be an array of what you have picked. You can pass these to your API. Full codepen here: https://codepen.io/cfjedimaster/pen/gOOjjrb?editors=1111

Have you tried to use the #select event? Vue Multiselect's documentation includes several events you can try, check it out here: https://vue-multiselect.js.org/#sub-events
So try
<multiselect v-model="value" :options="options" #select="actionToExecute" multiple></multiselect>
And then define that in your methods. I'm currently using vue multiselect too so let me know if that works for you.

Related

Selected values in a v-for loop of components

I implemented a component that have a select element inside and it is like following more or less:
<!-- child component -->
<template>
<b-form-select
v-model="selectedProject"
:options="projects"
#change="changedValue">
<template v-slot:first>
<option :value="null" disabled>-- Please select a project --</option>
</template>
</b-form-select>
</template>
<script>
export default {
name: 'AllocationItem',
props: {
projects: {
type: Array,
default: () => [{ value: Number}, { text: String}]
}
},
data() {
return {
selectedProject: null,
}
},
methods: {
changedValue(value) {
this.selectedProject = value;
}
}
}
</script>
I use this component in a parent componenent where it can be possible add other AllocationItem clicking on a button.
To do that i have used an array where i push a new item every time that there is a click on add button (i don't know if it's the right way...)
Follow parent component code:
<!-- parent component -->
<template>
<b-button class="btnAction" #click="addItem()">Add</b-button>
<b-button class="btnAction" #click="sendAllocation()">Send</b-button>
<b-row v-for="allocation in resourceItem.allocations" v-bind:key="allocation.id">
<allocation-item v-bind:projects="projects"></allocation-item>
</b-row>
</template>
<script>
export default {
name: 'Management',
components: {
AllocationItem
},
data() {
return {
allocations: []
}
},
methods: {
addItem() {
this.allocations.push(AllocationItem);
},
sendAllocation() {
this.allocations.forEach((allocation) => {
// I WOULD LIKE TO HAVE ALL SELECTED VALUE HERE!!!
});
},
},
created() {
const dataProjects = this.getProjectsData();
dataProjects.then(response => {
this.projects = response.map((item) => {
return {value: item.id, text: item.name}
})
});
}
</script>
In my application i have another button, send button, that should be read values selected in all child component (allocation-item).
How can i do to have an array with that selected values?
Thank you in advance to all
This depends on the relationship from your 'Send Button'-component with your parent component.
You can either:
Use the $emit() method to propagate data up the component tree to the shared parent component. Then prop it down to the 'Send Button'-component.
Have a single source of truth by using Vuex. This is a store that keeps all your data in a centralised object.
Perhaps you can provide us with more information on the project structure?
First of all, ask yourself if this component is being used anywhere else but here. If you only use it once, build it into the parent component and your problems are solved.
Otherwise I'd go with #laurensvm's approach of using emit or Vuex.
After some researches on google i have founded a solution. I don't know if it the right way but it works fine and it seems clean.
My solution consists to use emit on child component and v-model on parent like show following example.
<!-- child component -->
<template>
<b-form-select
v-model="selectedProject"
:options="projects"
#change="changedValue">
<template v-slot:first>
<option :value="null" disabled>-- Please select a project --
</option>
</template>
</b-form-select>
</template>
<script>
export default {
name: 'AllocationItem',
props: {
projects: {
type: Array,
default: () => [{ value: Number}, { text: String}]
},
value: {
type: Number
}
},
data() {
return {
selectedProject: this.value
}
},
methods: {
changedValue(value) {
this.$emit('input', value);
}
}
}
</script>
And on parent using an array variable on v-model.
Something like this:
<!-- parent component -->
<template>
<b-container>
<b-row>
<b-button class="btnAction" variant="success" #click="addItem(index)">Add</b-button>
<b-button class="btnAction" #click="sendAllocation(index)">Send</b-button>
</b-row>
<b-row v-for="(allocation, index) in resourceItem.allocations" v-bind:key="allocation.id">
<allocation-item v-bind:projects="projects" v-model="allocationItemSelected[index]"></allocation-item>
</b-row>
</b-container>
</template>
See a runnable example clicking on codesandbox link below:
https://codesandbox.io/s/vue-template-4f9xj?autoresize=1&expanddevtools=1&fontsize=14&hidenavigation=1&moduleview=1

Vuejs change prop value in component after select option component

I have 2 components, one creates an Editor using vue2-ace-editor, the other component is a select Option component. I Need to Change the theme of the Editor if I select another value in my select Option, so far my Editor component Looks like this:
<template>
<editor v-model="content" #init="editorInit" lang="javascript" theme="monokai"></editor> <!-- the default theme is monokai currently -->
</template>
<script>
export default {
props: [],
data () {
return {
language: 'javascript',
content: 'test',
}
},
components: {
editor: require('vue2-ace-editor'),
},
methods: {
editorInit () {
require('brace/ext/language_tools');
require('brace/mode/html');
require('brace/mode/javascript');
require('brace/mode/less');
require('brace/theme/clouds_midnight');
require('brace/theme/chrome');
require('brace/theme/ambiance');
}
},
}
</script>
And my select Option Looks like this:
<template>
<div>
<v-select
:items="themes"
v-model="themeSelection"
label="Select"
single-line
></v-select>
</div>
</template>
<script>
export default {
data () {
return {
themeSelection: null,
themes: [
{ text: 'ambiance' },
{ text: 'chrome' },
{ text: 'clouds_midnight' },
]
}
}
}
</script>
So basically if I select a different Option, I Need to Change the theme of the Editor, how do I manage this?

how to bind v-model to child component that contains input

I have some components that look like this.
<template>
<q-layout>
<v-input v-model="something" />
</q-layout>
</template>
<script>
import { QLayout } from 'quasar'
import { Input } from 'vedana'
export default {
name: 'index',
components: {
QLayout,
Input
},
data () {
return {
something: ''
}
}
}
this v-input component looks like this:
<template>
<input
:type="type ? type : 'text'"
class="v-input"/>
</template>
<script>
export default {
props: ['type'],
name: 'v-input'
}
</script>
When I enter data into the input something does not bind to whatever is in the value of the input that is inside of v-input.
How do I achieve this?
To enable the use of v-model the inner component must take a value property.
Bind the value to the inner <input> using :value, not v-model (this would mutate the prop coming from the parent). And when the inner <input> is edited, emit an input event for the parent, to update its value (input event will update the variable the parent has on v-model).
Also, if you have a default value for the type prop, declare it in props, not in the template.
Here's how your code should be
<template>
<input
:type="type"
:value="value"
#input="$emit('input', $event.target.value)"
class="v-input" />
</template>
<script>
export default {
props: {
type: {default() { return 'text'; }},
value: {} // you can also add more restrictions here
},
name: 'v-input'
}
</script>
Info about what props can have: Components / Passing data With Props.
Demo below.
Vue.component('v-input', {
template: '#v-input-template',
props: {
type: {default() { return 'text'; }},
value: {} // you can also add more restrictions here
},
name: 'v-input'
});
new Vue({
el: '#app',
data: {
something: "I'm something"
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<p>Parent something: {{ something }}</p>
<hr>
Child: <v-input v-model="something" />
</div>
<template id="v-input-template">
<input
:type="type"
:value="value"
#input="$emit('input', $event.target.value)"
class="v-input" />
</template>
https://v2.vuejs.org/v2/guide/components.html#sync-Modifier
<template>
<q-layout>
<v-input :value.sync="something" />
</q-layout>
</template>
<template>
<input
:type="type ? type : 'text'"
v-model="inputVal"
class="v-input"/>
</template>
<script>
export default {
props: ['type', 'value'],
name: 'v-input',
data:function(){
return {
inputVal: ''
};
},
watch:{
value: function(newValue){
this.$emit('update:value', newValue)
}
}
}
</script>
You need to pass your value to the input component using the .sync modifier so the changes will sync back to the parent.

Vue v-model changes parent data but doesn't change value prop in custom component

someone to help me with this strange issue?
I have the following vue component:
<template lang="pug">
div
p.alert.alert-info {{value}}
button(#click="onChange") Change
</template>
<script>
import Vue from 'vue';
export default {
name: 'z-temp',
props: {
value: {
required: true
}
},
watch: {
value(val) {
console.log(val);
}
},
methods: {
onChange() {
this.$emit('input', Random.id());
}
}
};
</script>
I want to use v-model, but when I use <z-temp v-model="myDataField">, the myDataField changes with success when I click in the Change button, but when I make the inverse and put some value in myDataField, like myDataField: "foo" the custom component gets this.value as undefined instead as foo.
Can anyone help me please?
I am guessing that myDataField is not reactive so the problem is in the parent.
Can you clarify the problem, seems like it is working as it should, ie. the component does not seem to be the problem.
zTemp = Vue.component('ztemp', {
template: '#ztemp',
props: {
value: {
required: true
}
},
watch: {
value(val) {
console.log(val);
}
},
methods: {
onChange() {
this.$emit('input', Math.random());
}
}
});
new Vue({
el: '#app',
components: {
zTemp
},
data: {
myinput: '0.2'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
{{myinput}}<br/>
<input v-model="myinput"/><br/>
<ztemp v-model="myinput"/><br/>
</div>
<script type="text/x-template" id="ztemp">
<div>
<p>{{value}}</p>
<button #click="onChange">Change</button>
</div>
</script>
thanks for helping, but I'm using meteor with vue-meteor, the problem was related to vue-meteor.
I changed the project structure to use separated Vue project in a .client folder and the problem gones. It was not a problema with component, but with vue-meteor package. Anyway, thank you guys.

Vue: v-model doesn't work with dynamic components

For example: <component v-model='foo' :is='boo' ...>.
foo's value stays the same during input.
I'm trying to solve the issue for quite a long time. I've checked lots of questions and threads but none of those helped me.
HTML doesn't work:
<component
:is="field.component"
:key="key"
:name="field.name"
v-for="(field, key) in integration_data"
v-model="field.value"
>
</component>
HTML works fine:
<input
:key="key"
:name="field.name"
v-for="(field, key) in integration_data"
v-model="field.value"
>
Vue controller:
export default {
init: function (init_data) {
return new Vue({
data: {
integration_data: [
{name: 'field_name0', component: 'input', value: ''},
{name: 'field_name0', component: 'input', value: ''},
]
},
});
}
}
You can't use input as a type of component and expect it to be a native input element. :is must name a component (which can contain an input, if you want).
Then you have to understand how v-model works on components:
So for a component to work with v-model, it should (these can be
configured in 2.2.0+):
accept a value prop
emit an input event with the new value
Putting that all together, you can use v-model with :is.
new Vue({
el: '#app',
data: {
integration_data: [{
name: 'one',
component: 'one',
value: 'ok'
}]
},
components: {
one: {
props: ['name', 'value'],
template: '<div>{{name}} and <input v-model="proxyValue"><slot></slot></div>',
computed: {
proxyValue: {
get() { return this.value; },
set(newValue) { this.$emit('input', newValue); }
}
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<component
:is="field.component"
v-for="(field, key) in integration_data"
:key="key"
:name="field.name"
v-model="field.value"
>
<div>{{field.value}}</div>
</component>
</div>
v-model has nothing to do with what you're possibly trying to do. It looks like you are trying to insert components dynamically. That's exactly what :is does. Now, to pass data to the component, you should use props.
For example:
Your Vue instance:
const vm = new Vue({
el: '#app',
data: {
exampleValue: 'This value will be passed to the example component'
}
})
Register a component:
Vue.component('example-component', {
// declare the props
props: ['value'],
template: '<span>{{ value}}</span>'
})
Then use it like this:
<example-component :value="exampleValue"></example-component>
Or:
<component :is="'example-component'" :value="exampleValue"></component>

Categories