I'm getting stuck on getting the data from my v-select input. Within console.log whenever I type it's just repeating an empty string with no data being sent.
Input
<v-select name="user" v-model="selectedUser" #select="testingMethod" #input="changeUser" label="user" :options="videos">
</v-select>
Data
data() {
return {
selectedUser:'',
}
Method
methods: {
changeUser: function() {
console.log(this.selectedUser)
}
}
#input event is triggered when you select an item not when you type, you could use #search event :
<v-select name="user" v-model="selectedUser" #select="testingMethod" #search="changeUser" label="user" :options="videos">
</v-select>
from my experience use #search or #change in order to read data at the typing event and #input for getting data from v-model after user clicked/selected or finished typing (when pressing enter key)
<v-select name="user" v-model="selectedUser" #search="changeUser" :options="videos">
then
Data
data() {
return {
selectedUser:'',
}
at method
methods: {
changeUser(input) {
console.log('typed data is ',input)
}
}
Try using #change instead of #input. Just a guess as I am not familiar with Vuetify controls which I am assuming v-select comes from.
Also, use :items instead of :options.
https://vuetifyjs.com/en/components/selects/#usage
<v-select name="user" v-model="selectedUser" #select="testingMethod" #change="changeUser" label="user" :items="videos">
</v-select>
Related
I've got a BaseCheckbox component which has been used to bind and trigger single boolean values.
<template>
<BaseCheckbox v-model="simpleBoolean" ... />
</template>
...
data() {
return { simpleBoolean: false }
}
Now, I want to bind multiple BaseCheckboxes via v-model to an array like its described in the docs.
<template>
<BaseCheckbox v-model="fruits" value="apple" />
<BaseCheckbox v-model="fruits" value="banana" />
</template>
...
data() {
return { fruits: [] }
}
However, I also want to keep the option to trigger simple boolean values within the same component. Here is an example project on stackblitz where you can reproduce my problem.
I want that fruits array is filled with the value of the checkbox like its done for nuts array. How to achieve this behaviour?
This may not be the best way to do it but it works.
First of all, modelValue is an array, not a boolean. Add this to your BaseCheckbox as an array to make it fill the array:
handleInput(id) {
if (!this.modelValue.includes(id)) {
this.$emit('update:modelValue', [...this.modelValue, id]);
} else {
this.$emit(
'update:modelValue',
this.modelValue.filter((value) => value !== id)
);
}
}
and then modify your input to remove checked:
<input :id="id" type="checkbox" v-bind="$attrs" #input="handleInput(id)" />
Also, modelValue should be an array, not a booleanright?
(Not sure whether this StackBlitz works.)
Firs of all here is my code:
<input type="text" id="first_name" class="form-control" v-model="user.attributes.first_name"
#keyup.enter="updateProfile" v-model.trim="$v.first_name.$model"
:class="{'is-invalid':$v.first_name.$error, 'is-valid':!$v.first_name.$invalid}">
I am using vuelidate in my form to validate my input field. But at the same time, I am getting the user object as a prop and I want to show the first name of the object as a value of the input field. Since I trim the value of the input field, I think I am not able to use v-model to show my value anymore. Do you have any solution for this?
First, you can't have multiple v-model on the same element.
Then, if you want to use a prop as a v-model, you have to set the #input event yourself.
cf vuelidate documentation
<template>
<input v-model.trim="$v.first_name.$model" #input="updateFirstname">
</template>
<script>
export default {
props: {
user: Object
},
validations: {
first_name: { ... }
},
methods: {
updateFirstName(newFirstName) {
this.user.attributes.first_name = newFirstName
this.$v.first_name.$touch()
}
}
}
</script>
I dynamically draw form input component (as in the image) using this code:
In this case the key can be "name","gruppo","codice" and so on.
<v-row>
<v-col v-for="(key,i) in keys_visible" :key="key" v-if="headers_visible[i].visible == true" cols="12" sm="12" md="12"
v-if="!(headers_visible[i].type == 'bit' && editedItem[key] == -9)">
<v-text-field #change="comp_change(key)" v-else-if="headers_visible[i].type == 'varchar'" v-model="editedItem[key]" :label="headers_visible[i].text"></v-text-field>
</v-col>
</v-row>
Then I have comp_change function which is defined in methods block:
comp_change (par1) {
var self = this;
self.editedItem["name"] = "example text";
},
I have placed a debugger; at the beginning of comp_change function, and it stops everytime so the function is triggered, but without displaying new value in "Nome" field (which v-model is editedItem["name"]). Why after comp_change I can't see "example text" in the field?
The form is already opened when I fire change
This is likely a reactivity issue. You should read up on this here. Also, if you use v-model, you do not need to set the value yourself, meaning you can do away with the #change call. You have two options as I see it.
a. Use root data objects on your component instead of an array/object and then use v-model as normal. This looks like:
<template>
<v-text-field v-model="name" />
<v-text-field v-model="email" />
</template>
<script>
export default {
data() {
return {
name: '',
email: '',
etc: ''
}
}
}
</script>
Now, when your form fields are updated by the user, you won't need to use #change to set the value. It will happen automatically.
b. Or, set the model with Vue.set(). In this case, you are not going to use v-model. Instead, you have defined your own methods to manage the data. This looks like:
<template>
<v-text-field #change="comp_change(key)" />
</template>
<script>
import Vue from 'vue';
export default {
data() {
return {
editedItem: {}
}
},
methods: {
comp_change (par1) {
Vue.set( this.editedItem, 'name', 'example text' );
}
}
}
</script>
I have this form on my parent:
<template>
<b-form #submit="onSubmit">
<CountryDropdown/>
</b-form>
</template>
<script>
import ...
export default {
form: {
country: ''
}
}
</script>
This is my Dropdown component using vue-select:
<template>
<v-select label="countryName" :options="countries" />
</template>
<script>
export default {
data() {
return {
countries: [
{ countryCode: 'EE', countryName: 'Estonia' },
{ countryCode: 'RU', countryName: 'Russia' }
]
}
}
}
</script>
I need to pass the countryCode value to its parent's form.country. I tried using $emit, but I cant seem to figure out how upon selection
it will set the parent value, and not upon submit.
EDIT:
The submitted solutions work great, I'll add my solution here:
I added an input event to my v-select:
<v-select #input="setSelected" ... />
in my script i define the selected and setSelected method :
data()
return
selected: ''
setSelected(value) {
this.selected = value.countryCode
this.$emit("selected", value.countryCode)
}
And in the parent:
<CountryDropdown v-on:selected="getCountry />
and parent script:
getCountry(country) {
this.form.country = country
}
You could use Vue's v-model mechanism to bind the output of vue-select to form.country in the container.
In CountryDropdown, implement v-model:
Add a prop named value 1️⃣, and bind it to vue-select.value 2️⃣
Emit input-event with the desired value. In this case, we want to emit countryCode as the value. 3️⃣
<template>
<v-select
:value="value" 2️⃣
#input="$emit('input', $event ? $event.countryCode : '')" 3️⃣
/>
</template>
<script>
export default {
props: ['value'], // 1️⃣
}
</script>
Now, the container of CountryDropdown could bind form.country to it, updating form.country to the selected country's countryCode upon selection:
<CountryDropdown v-model="form.country" />
demo
As you seem to know, $emit is what you need to use to send an event from a component to its' parent. To make that happen you need to add a few more things to your current code.
To get the options to list in your v-select you should use a computed function to isolate the names, like this:
computed: {
countryNames() {
return this.countries.map(c => c.countryName)
}
},
You will then need to list the names in your v-select like this:
<v-select label="countryName" :items="countryNames" #change="selectedCountry" />
You will see that #change is calling a method, this will be the method to emit your country code and it can do so like this:
methods: {
selectedCountry(e) {
let code = this.countries.find(cntry => cntry.countryName === e)
this.$emit('code', code.countryCode)
}
},
You will need a listener in your parent to hear the emit, so add something like this:
<CountryDropdown v-on:code="countryCodeFunction"/>
And then you just need a countryCodeFunction() in your methods that does something with the emitted code.
I have a lot of forms to create in a web app I'm working on, for which I'm using Vue, so I've been trying to create a generic input component I can use throughout. I'm using Bootstrap grids, so the idea is that I should be able to pass the component a number of columns to take up, a label, a name and a property to use as the v-model. I'm kind of getting there, I think, but I'm running into a problem with mutating props - [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "model"
(found in component ).
Here's the template (in simplified form):
<template id="field">
<div v-bind:class="colsClass">
<div class='form-group form-group-sm'>
<label v-bind:for="name">{{labelText}}</label>
<input v-bind:id='name' ref="input" class='form-control' v-bind:name='name' v-model='model'/>
</div>
</div>
And here's the (again simplified) JS:
Vue.component('field', {
template: '#field',
props: ['cols','label','group','name','model'],
computed:{
colsClass:function(){
return "col-xs-"+this.cols
}
,
labelText:function(){
if(this.label) {
return this.label
} else {
return _.startCase(this.name);
}
}
}
});
This is used from within another 'edit-product' component, like this:
<field :cols="8" name="name" :model="product.name"></field>
This displays OK, but throws the error (or more accurately, warning), when I edit the value of the field. So what am I doing wrong?
Actually, the solution I've gone for is rather simpler than the one suggested above, very simple in fact, taken from https://forum-archive.vuejs.org/topic/4468/trying-to-understand-v-model-on-custom-components/9.
I don't want the 'model' prop, I have a 'value' one instead, so the JS is changed to this:
Vue.component('field', {
template: '#field',
props: ['cols','label','group','name','value'],
computed:{
colsClass:function(){
return "col-xs-"+this.cols
}
,
labelText:function(){
if(this.label) {
return this.label
} else {
return _.startCase(this.name);
}
}
}
});
The template becomes this:
<div class='form-group form-group-sm'>
<label :for="name">{{labelText}}</label>
<input :id='name' :name='name' class='form-control' :value="value" #input="$emit('input', $event.target.value)"/>
</div>
</div>
And I use it like this:
<field :cols="8" name="name" v-model="product.name"></field>
The difference is that I'm not actually trying to pass a model prop down, I'm just passing a value, and listening for changes to that value. It seems to work pretty well and is clean and simple enough. My next challenge is passing an arbitary set of attributes to the input, but that's the subject of another question.
As the warning suggests you should not directly edit the prop you are passing for the value.
Instead use this as the original value and set a seperate value on the input from it - which you can pass to the v-model. If you need the parent to have the current value then also pass a prop that will allow you to update the param on the parent, i.e.
input component
# script
props: [
'origValue',
'valueChange',
],
data: {
inputValue: '',
...
},
mounted () {
this.inputValue = this.origValue
},
watch: {
inputValue () {
this.valueChange(this.inputValue)
},
...
},
...
# template
<input type="text" v-model="inputValue">
parent
# script
data () {
return {
fieldValue: 'foo',
...
},
},
methods: {
updateField (value) {
this.fieldValue = value
},
...
},
...
# template
<field :value-change="updateField" :orig-value="fieldValue"></field>