Vue El-Select doesn't work as expected while passing value from parent to child using watch - vue.js

Component A
<el-select v-model="value" placeholder="Select Action" #change="updateDropdowns($event)" prop="action">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<tableview
:action="this.value"
v-show="false">
</tableview>
<script>
export default {
name: 'warehouseAdd',
components: {
tableview
},
props: [
'component'
],
data() {
return {
options: [
{
value: 'add',
label: 'Add'
}, {
value: 'edit',
label: 'Edit'
}
],
value: '',
Component B
<script>
props: [
'action'
],
watch: {
'action': function (value) {
console.log(value);
//Select value from dropdown doesn't pass the value at 1st attempt.
//If I again select the value from dropdown then I get the value.
}
}
Here whenever I try to get value.. I am unable to get value on first event. I need value once I select value from dropdown. I might be doing something wrong not exactly sure.. new to VueJs.
Please let me know how do I pass value at 1st instance to Component B.
Although I am getting the value in Component A on first attempt just not getting at Component B
I am able to fetch dropdown value in parent component but unable to fetch the same in child component when I initially select the value for 1st time. When I change the value of dropdown 2nd time then I get the value in child component.
Thanks!

In your question title you said that El-Select doesn't work as expected. Actually it works as expected. When you reload the page, all Vue data come back to their initial values. So when you set value: '' in component A (that I called it parentTable in my following codes), then after reloading the page the value of '' comes back to that value data. If you want to store the value of selected item before reloading page, there are some solutions to that. One of them is using Window localStorage. Here is the codes that works for me:
parentTable.vue component:
<template>
<div>
<el-select v-model="value" placeholder="Select Action">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<tableview
:action="this.value"
v-show="false">
</tableview>
</div>
</template>
<script>
import tableview from "./tableview";
export default {
name: "parentTable",
components: {
tableview
},
data() {
return {
options: [
{
value: 'add',
label: 'Add'
}, {
value: 'edit',
label: 'Edit'
}
],
value: null,
}
},
watch: {
value: function (newVal) {
this.getValueOf(newVal);
}
},
methods: {
getValueOf: function (storeValue) {
localStorage.setItem("option", storeValue);
}
},
mounted() {
/* Here we get the previous selected item from localStorage */
this.value = localStorage.getItem("option");
}
}
</script>
<style scoped>
</style>
tableview.vue component:
<template>
</template>
<script>
export default {
name: "tableview",
props: [
'action'
],
watch: {
action: function (value) {
console.log(value);
}
}
}
</script>
<style scoped>
</style>

Related

v-select component is not showing selected option in v-select box

I am facing one problem while working with v-select component. V-select component is not showing selected item... It is showing options in dropdown but after selecting it is showing blank in select box.
This is the problem-
Dropdown is showing.. but not showing anything after selecting.
Like this.. It is blank.
Here is my code
<template>
<div>
<v-select
label="broadcast"
v-model="broadcast_"
:options="broadcasters"
:reduce="(broadcast) => broadcast.id"
>
<template v-slot:option="option">{{ option.name }}</template>
</v-select>
</div>
</template>
<script>
import Vue from "vue";
import vSelect from "vue-select";
Vue.component("v-select", vSelect);
export default {
data() {
return {
broadcasters: [
{
name: "ABC Live",
id: 1,
},
{
name: "Disney",
id: 3,
},
{
name: "24x7 Broadcast",
id: 4,
},
],
broadcast_: "",
};
},
watch: {
broadcast_(val) {
console.log(val); //It prints desire data (i.e broadcast id)
},
},
};
</script>
I don't know exactly what you wanted with your :reduce statement.
But if you change your code where
label="broadcast"
to
label="name"
or
label="id"
You will get the text in the selectbox

Select first option by default using v-model

Can someone help with this problem? I have a dynamic select dropdown. The first default option of "Choose your location" is not visible by default. This is because of v-model. How can I get that working?
My parent component:
<template>
<div>
<Segments #select-segment-location-event="updateSegmentLocation" :segmentLocation="segmentLocation" />
</div>
</template>
My child component:
<template>
<div class="container">
<select v-model="segmentLocation" #change="selectSegmentLocation">
<option selected disabled>Choose your location...</option>
<option v-for="(segLoc, index) in segmentLocations"
:key="index"
:value="segLoc">{{ segLoc.name }}</option>
</select>
</div>
</template>
<script>
export default {
data() {
return {
segmentLocations: [
{ value: "Residential", name: 'Residential building' },
{ value: "Workplace", name: 'Workplace' },
{ value: "Hospitality", name: 'Hospitality or Retail' },
{ value: "Real Estate", name: 'Real Estate' },
{ value: "Commercial Parking", name: 'Commercial Parking' },
{ value: "Fleets", name: 'Fleets' },
{ value: "Cities & Governments", name: 'Cities & Governments' },
{ value: "Corridor", name: 'Highway, Corridor or Petrol Station' }
],
}
}
methods: {
selectSegmentLocation() {
this.$emit('select-segment-location-event', this.segmentLocation);
}
}
};
</script>
From what I see, the segmentLocation variable is passed as a prop to the Segments component.
You should avoid mutating a prop with v-model in the child component, because each component should only mutate it's own state.
I propose a few changes, add a new selectedSegmentLocation variable in your data method, with a default value of "NOT_SELECTED" :
data() {
return {
selectedSegmentLocation: "NOT_SELECTED",
segmentLocations: []
}
}
Then, in your template, update the Choose your location... option to have a value attribute:
<option selected value="NOT_SELECTED" disabled>Choose your location...</option>
Now, update the v-model and the selectSegmentLocation method to use the new variable:
<select v-model="selectedSegmentLocation" #change="selectSegmentLocation">
selectSegmentLocation() {
this.$emit('select-segment-location-event', this.selectedSegmentLocation);
}
If you still want to use the passed prop segmentLocation as a default value, use it in the created() hook, but you should have 'NOT_SELECTED' as the default value if you want to show the 'Choose your location' option.
created() {
this.selectedSegmentLocation = this.segmentLocation ? this.segmentLocation : "NOT_SELECTED";
}
And, if you want to be able to change the selected value from the parent, you can watch the segmentLocation property:
watch: {
segmentLocation() {
if (this.segmentLocation) {
this.selectedSegmentLocation = this.segmentLocation;
}
}
}

How to fire on change event of select while setting v-model?

I have Dropdown.vue and Sprint.vue use Dropdown.vue
Dropdown.vue code
<template>
<div>
<select
v-model="selected"
#input="$emit('input', $event.target.value)"
#change="emitChangeEvent"
>
<option
v-for="(option, idx) in options"
:key="`option-${idx}`"
:value="option.value"
>
{{ option.text }}
</option>
</select>
</div>
</template>
<script>
export default {
name: 'Dropdown',
props: {
options: {
type: Array,
default: () => [],
},
value: {
required: false,
},
},
computed: {
selected: {
get() {
return this.value;
},
set(newValue) {},
},
},
methods: {
emitChangeEvent() {
this.$emit('change', this.selected);
},
},
};
</script>
In Sprint.vue
<template>
<div>
<Dropdown
v-model="sprint"
:options="sprints"
#change="sprintChanged"
/>
{{ sprint }}
<button #click="change">
Change Sprint
</button>
</div>
</template>
<script lang="ts">
import {
Component, Prop, Vue, Emit,
} from 'vue-property-decorator';
import Dropdown from '#/components/Dropdown.vue';
#Component({
components: {
Dropdown,
},
})
export default class Sprint extends Vue {
private sprint = {};
private sprints = [
{ text: 'Sprint A', value: 'A' },
{ text: 'Sprint B', value: 'B' },
{ text: 'Sprint C', value: 'C' },
];
change() {
this.sprint = 'B';
}
sprintChanged(value: any) {
console.log(`value=${value}, sprint=${this.sprint}`);
}
}
</script>
When we select an option, an event was fired. But when I click on the button to set selected option by programming, there is no event of select is fired.
What am I missing?
As far as I can see, there are two main problems in your Dropdown.vue component.
1) You are binding the v-model of the element to the computed property selected, and emitting selected in your emitChangeEvent
2) and the selected computed properties doesn't have a setter so nothing happens when the value change.
To check if this is the only problem, a quick solution is to change your emitChangeEvent to this:
emitChangeEvent(event) {
this.$emit('change', event.target.value);
}
Emitting directly the value from event will skip any problem in the definition of the computed property.

Vue.js - Select / dropdown selected item vm binding is not working (bootstrap-vue)

I'm trying to create a simple vue that binds the selected item from a select/dropdown to a property in the vm.
I haven't been able to find a clear and simple example of how this is down when using an options collection that is also in the view model.
<template>
<div>
<h1>Select box</h1>
<b-dropdown id="ddCommodity"
name="ddCommodity"
v-model="ddTestVm.ddTestSelectedOption"
text="Select Item"
variant="primary"
class="m-md-2" v-on:change="changeItem">
<b-dropdown-item disabled value="0">Select an Item</b-dropdown-item>
<b-dropdown-item v-for="option in ddTestVm.options":selected="option.value == 'LME/ST_TNI_ALL'":value="option.value">{{option.text}}</b-dropdown-item>
</b-dropdown> <span>Selected: {{ ddTestVm.ddTestSelectedOption }}</span>
</div>
</template>
<script>
export default {
components: {
},
data() {
return {
someOtherProperty: null,
ddTestVm: {
originalValue: [],
ddTestSelectedOption: "Value1",
disabled: false,
readonly: false,
visible: true,
color: "",
options: [
{
"value": "Value1",
"text": "Value1Text"
},
{
"value": "Value2",
"text": "Value2Text"
},
{
"value": "Value3",
"text": "Value3Text"
}
]
}
}
},
methods: {
changeItem: async function () {
//grab some remote data
try {
let response = await this.$http.get('https://www.example.com/api/' + this.ddTestVm.ddTestSelectedOption + '.json');
console.log(response.data);
this.someOtherProperty = response.data;
} catch (error) {
console.log(error)
}
}
},
watch: {
},
async created() {
}
}
</script>
<style>
</style>
Regardless of what i've tried i cannot get the selected value in the dropdown to change the ddTestSelectedOption property of the vm.
Could anyone assist on this issue?
Thanks.
b-dropdown in bootstrap-vue does not support v-model. As the documentation states:
Dropdowns are toggleable, contextual overlays for displaying lists of
links and actions in a dropdown menu format.
In other words, b-dropdown is essentially a UI component for displaying a menu or similar set of options.
I expect what you want is b-form-select.
That said, you could add a click handler to the options that sets the value.
<b-dropdown-item v-for="option in ddTestVm.options"
:key="option.value"
:value="option.value"
#click="ddTestVm.ddTestSelectedOption = option.value">
Here is a working example.
I thing you need b-form-select
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
<b-form-select v-model="selected" :options="options" size="sm" class="mt-3"></b-form-select>
<div class="mt-3">Selected: <strong>{{ selected }}</strong></div>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: null, text: 'Please select an option' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Selected Option' },
{ value: { C: '3PO' }, text: 'This is an option with object value' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
Only b-form-select can achieve the selected value behaviour.
Non-Selected Value Preview:
Selected Value Preview:
Sample Code:
<template>
<div>
<b-form-select v-model="selected" :options="options"></b-form-select>
</div>
</template>
<script>
export default {
data() {
return {
selected: null,
options: [
{ value: 1, text: 'Please select an option' },
{ value: 2, text: 'This is First option' },
{ value: 3, text: 'Selected Option' }
]
}
}
}
</script>
Wanted to leave a comment, but code example looks pale there :)
Yes, b-dropdown does not properly support Vue model, but it doesn't have to.
For those still interested in exactly dropdown (f.e. because it looks fancier), consider:
<b-dropdown :text="$i18n.locale" >
<b-dropdown-item v-for="(lang, i) in $i18n.availableLocales" :key="`Lang${i}`" :value="lang" v-on:click="$i18n.locale = lang;" >{{lang}}</b-dropdown-item>
</b-dropdown>
Slecifically v-on:click, which can handle the model value change for you.

VueJs: Textarea input binding

I'm trying to figure out how to detect change of the value on the textarea from within the component.
For input we can simply use
<input
:value="value"
#input="update($event.target.value)"
>
However on textarea this won't work.
What I'm working with is the CKEditor component, which should update wysiwyg's content when model value of the parent component (attached to this child component) is updated.
My Editor component currently looks like this:
<template>
<div class="editor" :class="groupCss">
<textarea :id="id" v-model="input"></textarea>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: ''
},
id: {
type: String,
required: false,
default: 'editor'
}
},
data() {
return {
input: this.$slots.default ? this.$slots.default[0].text : '',
config: {
...
}
}
},
watch: {
input(value) {
this.update(value);
}
},
methods: {
update(value) {
CKEDITOR.instances[this.id].setData(value);
},
fire(value) {
this.$emit('input', value);
}
},
mounted () {
CKEDITOR.replace(this.id, this.config);
CKEDITOR.instances[this.id].setData(this.input);
this.fire(this.input);
CKEDITOR.instances[this.id].on('change', () => {
this.fire(CKEDITOR.instances[this.id].getData());
});
},
destroyed () {
if (CKEDITOR.instances[this.id]) {
CKEDITOR.instances[this.id].destroy()
}
}
}
</script>
and I include it within the parent component
<html-editor
v-model="fields.body"
id="body"
></html-editor>
however, whenever parent component's model value changes - it does not trigger the watcher - effectively not updating the editor's window.
I only need update() method to be called when parent component's model fields.body is updated.
Any pointer as to how could I approach it?
That's a fair bit of code to decipher, but what I would do is break down the text area and the WYSIWYG HTML window into two distinct components and then have the parent sync the values, so:
TextArea Component:
<template id="editor">
<textarea :value="value" #input="$emit('input', $event.target.value)" rows="10" cols="50"></textarea>
</template>
/**
* Editor TextArea
*/
Vue.component('editor', {
template: '#editor',
props: {
value: {
default: '',
type: String
}
}
});
All I'm doing here is emitting the input back to the parent when it changes, I'm using input as the event name and value as the prop so I can use v-model on the editor. Now I just need a wysiwyg window to show the code:
WYSIWYG Window:
/**
* WYSIWYG window
*/
Vue.component('wysiwyg', {
template: `<div v-html="html"></div>`,
props: {
html: {
default: '',
type: String
}
}
});
Nothing much going on there, it simply renders the HTML that is passed as a prop.
Finally I just need to sync the values between the components:
<div id="app">
<wysiwyg :html="value"></wysiwyg>
<editor v-model="value"></editor>
</div>
new Vue({
el: '#app',
data: {
value: '<b>Hello World</b>'
}
})
Now, when the editor changes it emits the event back to the parent, which updates value and in turn fires that change in the wysiwyg window. Here's the entire thing in action: https://jsfiddle.net/Lnpmbpcr/