v-select doesn't recognize label prop - vue.js

I'm working on a VueJs file and try to use <v-select> so what I'm doing is that :
<v-select :options="divisions" label="text" ></v-select>
and my divisions is an array of object conatining id and text but when i'm going on my page I have <% getOptionLabel(option) %> instead of the text value for each one of my divisions value
here is a screenshot of console.log(this.divisions) :
So this is my code :
<form id="MassUpdateDivisionForm">
<v-select v-bind:label="text" :options="divisions"></v-select>
</form>
<script>
import vSelect from "js/vue-select/vue-select.js"
export default {
props: ['product'],
components: {vSelect},
data() {
return {
divisions: []
}
}
methods: {
getDivisions(){
let self = this
this.$http({
url: 'divisions',
method: 'get'
}).then((response)=>{
self.$set('divisions', response.data)
console.log(self.divisions)
//that's where I got the pic
},(response)=>{
alert('something went wrong')
}
)
}
},
created () {
this.getDivisions()
},
}
</script>

If I am understanding you correctly, you want the text attribute of the selected option to be displayed as the label? If so, you will need to pass the data of the selected option back to the <v-select>. You can emit an event on change to change label to the text value, but make sure you bind to the label attribute using either v-bind:label=textor the shorthand :label=text

I just had the same problem and solved it by passing the name of the label as a string.
<v-select :options="warehouses" :label="'name'"></v-select>
or you could do it with an html attribute without vue binding.
<v-select :options="warehouses" label="name"></v-select>
Cheers,

Related

How to make a checkbox selected by default in VueJs?

EDIT: My problem has shifted somewhat, with a different code focus, so I created a new question.
I have a Beufy Form Field Component, with a Boolean Input Checkbox inside, this Form Field Component allows you to select the option "Later" and this disables the Form Field and Checkbox. I would like to have it so that when "Later" is selected, the Boolean Input Checkbox is ticked/enabled by default.
I've read the Buefy checkbox documentation and I can see that I should use
<b-checkbox :value="true"
but when I attempt add it to my FormField template (the checkbox is a child component of the Form Field component) call it throws errors, this is how the template is rendered:
<FormField
:for="param.editableByOperator"
:label="null"
:disabled="param.populationStrategy.value === 'later'"
:checked="checked"
as="Boolean">
</FormField>
How do I best implement this fix? I'll attach the Checkbox Component
Below:
<template>
<b-checkbox
v-model="localValue"
:name="$props.name"
:checked="checked">
{{label}}
</b-checkbox>
</template>
<script>
import BaseInput from './BaseInput';
export default {
name: 'BooleanInput',
mixins: [BaseInput],
props: {
checked: {
type: Boolean,
default: true,
},
}
};
</script>
edit:
In my component I have found these methods, which set the checkbox as unticked by default. Is there something I can do here which would set the checkbox(editableByOperator) to True when 'Later'(populationStrategy) is set to 'Later.
Methods:
drawMonadParams(monadSlug) {
const monad = this.ccMonad(monadSlug);
monad.params.forEach((x, idx) => {
this.addFormFields(['params', idx], {
value: this.defaultMonadParamValue(x.typeSlug),
populationStrategy: 'now',
editableByOperator: false,
ccRequestParamId: null,
name: x.name,
typeSlug: x.typeSlug,
});
});
},
defaultMonadParamValue(typeSlug) {
return typeSlug === 'boolean' ? false : '';
},
May be try not using the checked prop inside the template . Try a data variable and use that instead.
like this
<b-checkbox :checked="checkValue"></b-checkbox>
props(){
checked:{
type:Boolean,
default:true
}
data(){
return{
checkValue : this.checked
}
}

sending drop-down value to parent

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.

Vue.js this.$refs empty due to v-if

I have a simple Vue component that displays an address, but converts into a form to edit the address if the user clicks a button. The address field is an autocomplete using Google Maps API. Because the field is hidden (actually nonexistent) half the time, I have to re-instantiate the autocomplete each time the field is shown.
<template>
<div>
<div v-if="editing">
<div><input ref="autocomplete" v-model="address"></div>
<button #click="save">Save</button>
</div>
<div v-else>
<p>{{ address }}</p>
<button #click="edit">Edit</button>
</div>
</div>
</template>
<script>
export default {
data() {
editing: false,
address: ""
},
methods: {
edit() {
this.editing = true;
this.initAutocomplete();
},
save() {
this.editing = false;
}
initAutocomplete() {
this.autocomplete = new google.maps.places.Autocomplete(this.$refs.autocomplete, {});
}
},
mounted() {
this.initAutocomplete();
}
}
I was getting errors that the autocomplete reference was not a valid HTMLInputElement, and when I did console.log(this.$refs) it only produced {} even though the input field was clearly present on screen. I then realized it was trying to reference a nonexistent field, so I then tried to confine the autocomplete init to only when the input field should be visible via v-if. Even with this, initAutocomplete() is still giving errors trying to reference a nonexistent field.
How can I ensure that the reference exists first?
Maybe a solution would be to use $nextTick which will wait for your DOM to rerender.
So your code would look like :
edit() {
this.editing = true;
this.$nextTick(() => { this.initAutocomplete(); });
},
Moreover if you try to use your this.initAutocomplete(); during mounting it cannot work since the $refs.autocomplete is not existing yet but I'm not sure you need it since your v-model is already empty.
I think it's because your "refs" is plural
<input refs="autocomplete" v-model="address">
It should be:
<input ref="autocomplete" v-model="address">

How do I insert object created with document.createElement into template?

I like to know how I can insert a Element that has already been created with the document.createElement method into the template. I am not sure how to proceed here because eventually I would also like to bind the contents of that particular textBox. Here is the (non working) code that I have up till now to illustrate what I like to do:
<template>
<div>
<p id="status">{{ statusMessage }}</p>
<div id="output" v-html="textBox"></div>
</div>
</template>
<script>
export default {
name: 'Result',
data() {
return {
statusMessage: "Status",
textBox: Object,
}
},
mounted() {
this.textBox = this.$someModule.createTextBox()
console.log('textBox should become: '+this.textBox)
// Shows: textbox should become: [object HTMLTextAreaElement]
},
...
}
First of all, v-html is a directive that allow you to use raw html text.
ref: https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
Second of all, you can you a ref directive to create a link to you element (ref="someName"):
<div id="output" ref="textBox"></div>
Then:
const el = this.$refs.textBox;
el.appendChild('entity which you want to append');

Trying to create generic input component

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>