Bootstrap-vue: how can I display the text of a selected item? - vue.js

I am using Bootstrap Vue to render a select input. Everything is working great - I'm able to get the value and change the UI based on the option that was selected.
I am trying to change the headline text on my page - to be the text of the selected option. I am using an array of objects to render the options in my select input.
Here is what I'm using for my template:
<b-form-group
id="mySelect"
description="Make a choice."
label="Choose an option"
label-for="mySelect">
<b-form-select id="mySelect"
#change="handleChange($event)"
v-model="form.option"
:options="options"/>
</b-form-group>
Here is what my data/options look like that I'm passing to the template:
...
data: () => ({
form: {
option: '',
}
options: [
{text: 'Select', value: null},
{
text: 'Option One',
value: 'optionOne',
foo: {...}
},
{
text: 'Option Two',
value: 'optionTwo',
foo: {...}
},
}),
methods: {
handleChange: (event) => {
console.log('handleChange called');
console.log('event: ', event); // optionOne or optionTwo
},
},
...
I can get optionOne or optionTwo, what I'd like to get is Option One or Option Two (the text value) instead of the value value. Is there a way to do that without creating an additional array or something to map the selected option? I've also tried binding to the actual options object, but haven't had much luck yet that route either. Thank you for any suggestions!
Solution
Thanks to #Vuco, here's what I ended up with. Bootstrap Vue passes all of the select options in via :options. I was struggling to see how to access the complete object that was selected; not just the value.
Template:
<h1>{{ selectedOption }}</h1>
<b-form-group
id="mySelect"
description="Make a choice."
label="Choose an option"
label-for="mySelect">
<b-form-select id="mySelect"
v-model="form.option"
:options="options"/>
</b-form-group>
JS:
...
computed: {
selectedOption: function() {
const report = this.options.find(option => option.value === this.form.option);
return option.text; // Option One
},
methods: {
//
}
...
Now, when I select something the text value shows on my template.

I don't know Vue bootstrap select and its events and logic, but you can create a simple computed property that returns the info by the current form.option value :
let app = new Vue({
el: "#app",
data: {
form: {
option: null,
},
options: [{
text: 'Select',
value: null
},
{
text: 'Option One',
value: 'optionOne'
},
{
text: 'Option Two',
value: 'optionTwo'
}
]
},
computed: {
currentValue() {
return this.options.find(option => option.value === this.form.option)
}
}
});
<div id="app">
<b-form-group id="mySelect" description="Make a choice." label="Choose an option" label-for="mySelect">
<b-form-select id="mySelect" v-model="form.option" :options="options" />
</b-form-group>
<p>{{ currentValue.text }}</p>
</div>
Here's a working fiddle.

You have an error in your dictionary.
Text is showed as an option.
Value is what receive your variable when option is selected.
Is unneccesary to use computed property in this case.
let app = new Vue({
el: "#app",
data: {
form: {
option: null,
},
options: [{
value: null,
text: 'Select'
},
{
value: 'Option One',
text: 'Option One'
},
{
value: 'Option Two',
text: 'Option Two'
}
]
}
});
Fiddle with corrections
Documentation

Related

Bootstrap-vue Checkbox, Check additional options when selected

What i want to do is also check the default option when a user checks one of the checkbox item.
i have created a snippet of the error i am encountering,
usually i thought its because of my nested components.
but i encountered the error
You may have an infinite update loop in watcher with expression "localChecked"
even on this simple code snippet.
vue js script
new Vue({
el: "#app",
data: {
application: [
{
app_name : 'Netflix',
app_default : 'videoshare_default',
options : [
{ text : 'Video Stream', value : 'video_streaming'},
{ text : 'Download Video' , value : 'video_download'},
{ text : 'Share Video' , value : 'videoshare_default'}
]
},
{
app_name : 'Messenger',
app_default : 'message',
options : [
{ text : 'Messaging', value : 'message'},
{ text : 'Voice Calls' , value : 'voice_calls'},
{ text : 'Video Calls' , value : 'video_calls'},
{ text : 'Media Sharing' , value : 'file_transfer'}
]
}
],
selected : []
},
methods: {
selectDefault: function(data,$event){
this.selected[data.app_name].push(data.videoshare_default)
}
}
})
HTML
<div id="app">
<b-col v-for="(data , index) in application" v-bind:key="index" class="p-2" cols="5">
<b-form-group :label="data.app_name" label-class="font-weight-bold">
<b-form-checkbox-group
#input="selectDefault(data,$event)"
v-model="selected[data.app_name]"
:options="data.options"
name="application[]"
stacked
></b-form-checkbox-group>
</b-form-group>
</b-col>
</div>
a FIDDLE:
https://jsfiddle.net/tomexsans/194m0jdq/1/
or is there any other way to do this than what i am doing.
Your selected property is an array, but you want to use key value pairs, which is why you need to make it an object instead, which will store an array of each application type.
To make sure that Vue stays reactive, you need to use the Vue.set or this.$set method to add a property to an object, if that property DOESN'T already exist in that object.
The $event on b-form-checkbox-group returns the entire array of selected values, which we don't want. That's why i use the .native modifier on the event, so i can access the clicked checkbox and it's value.
new Vue({
el: "#app",
data: {
application: [{
app_name: 'Netflix',
app_default: 'videoshare_default',
options: [{
text: 'Video Stream',
value: 'video_streaming'
},
{
text: 'Download Video',
value: 'video_download'
},
{
text: 'Share Video',
value: 'videoshare_default'
}
]
},
{
app_name: 'Messenger',
app_default: 'message',
options: [{
text: 'Messaging',
value: 'message'
},
{
text: 'Voice Calls',
value: 'voice_calls'
},
{
text: 'Video Calls',
value: 'video_calls'
},
{
text: 'Media Sharing',
value: 'file_transfer'
}
]
}
],
selected: {}
},
methods: {
selectDefault(data, event) {
/* Return if the checkbox was unchecked */
if (!event.target.checked) return;
/* Return if the selected value was the default */
if (data.app_default === event.target.value) return;
/* Init the array if it doesn't exist yet.*/
if (!this.selected[data.app_name]) {
this.$set(this.selected, data.app_name, []);
}
const nestedSelected = this.selected[data.app_name];
/* Push in the default value if it doesn't exist alreayd */
if (!nestedSelected.find(value => value === data.app_default)) {
this.selected[data.app_name].push(data.app_default)
}
}
}
})
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.3.0/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.3.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-col v-for="(data , index) in application" v-bind:key="index" class="p-2" cols="5">
<b-form-group :label="data.app_name" label-class="font-weight-bold">
<b-form-checkbox-group
v-model="selected[data.app_name]"
#input.native="selectDefault(data, $event)"
:options="data.options"
name="application[]"
stacked
></b-form-checkbox-group>
</b-form-group>
</b-col>
{{ selected }}
</div>

Adding img attribute to options in b-select component

I would like to add HTML img attribute to the b-form-select component of boostrap-vue inside to load img with each option?
<template>
<div>
<b-form-select v-model="selected" :options="options"></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 some item' },
{ value: 'a', text: 'This is First option' },
{ value: 'b', text: 'Default Selected Option' },
{ value: 'c', text: 'This is another option' },
{ value: 'd', text: 'This one is disabled', disabled: true }
]
}
}
}
</script>
It seems bootstrap-vue and bootstrap have different implementations on select components. And bootstrap-vue doesn't support thumbnails and it uses native select and options elements which makes impossible to set background image. Instead you can emulate dropdown component like select as below :
Template
<template>
<div class="hello">
<div class="back"></div>
<b-dropdown :text="selected ? selected.text : 'Please select some item'">
<b-dropdown-item
:disabled="option.disabled"
#click="select(option)"
v-for="option in options"
:key="option.value"
>
<div>
<img :src="option.src">
{{option.text}}
</div>
</b-dropdown-item>>
</b-dropdown>
</div>
</template>
Component
export default {
name: "HelloWorld",
props: {
msg: String
},
data() {
return {
selected: null,
options: [
{
value: null,
text: "Please select some item",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "a",
text: "This is First option",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "b",
text: "Default Selected Option",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "c",
text: "This is another option",
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
},
{
value: "d",
text: "This one is disabled",
disabled: true,
src: "https://mdn.mozillademos.org/files/7693/catfront.png"
}
]
};
},
methods: {
select(option) {
console.log(option);
this.selected = option;
}
}
};
Sandbox
Just like Bootstraps's custom select component BootstrapVue's <b-form-select> is based on <select>, which by HTML5 standards does not support complex HTML content in <option> elements.
If you need complex content (i.e. images, etc) in the options, you would need to create a custom component (probably based on <b-dropdpwn>) that allows you to use custom HTML5 in the "options" (dropdown items) and emulate the native select features.

Vue: binding with v-model in custom checkbox component doesn't work

I'm trying to build a custom checkbox component with options that are generated with a v-for loop from an array with options and values. How can I bind the v-model correctly to the checkbox component so that it's correctly updated?
The problem now is that the model only updates to the latest checkbox that is checked and does not give an array with all checked options.
Vue.component('ui-checkbox', {
props: {
label: {
type: String,
required: true,
},
index: {
type: Number
},
inputValue: {
type: String
}
},
methods: {
onChange(e) {
this.$emit('input', e.target.value);
},
},
template: `<div>
<input
:id="index"
type="checkbox"
:value="inputValue"
#change="onChange" />
<label :for="index">
{{ label }}
</label>
</div>`,
})
new Vue({
el: "#app",
data: {
checkOptions: [
{
label: 'Option 1',
value: 'value of option 1',
},
{
label: 'Option 2',
value: 'value of option 2',
},
{
label: 'Option 3',
value: 'value of option 3',
},
{
label: 'Option 4',
value: 'value of option 4',
},
],
myCheckBoxModel: []
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<span>checked Checkboxes: {{ myCheckBoxModel }} </span>
<ui-checkbox
v-for="(option, index) in checkOptions"
v-model="myCheckBoxModel"
:key="index"
:index="index"
:input-value="option.value"
:label="option.label" />
</div>
When you do
this.$emit('input', e.target.value);
it works like
myCheckBoxModel = e.target.value
So it just assigns the value of the last checkbox you clicked to myCheckBoxModel.
If you want to keep all checked items in myCheckBoxModel, you need to do the following:
add value property to ui-checkbox component to have access to the current value of myCheckBoxModel. Value is default property name for this goal (see vue guide).
in your onChange method copy the current value to the variable, because it's not good to mutate value property directly
if your checkbox is checked, push the correspondent value to the array. If the checkbox is not checked, delete to correspondent value from the array
emit input event with the resulting array as value
Vue.component('ui-checkbox', {
props: {
label: {
type: String,
required: true,
},
index: {
type: Number
},
inputValue: {
type: String
},
value: {
type: Array
}
},
methods: {
onChange(e) {
let currentValue = [...this.value]
if (e.target.checked) {
currentValue.push(e.target.value)
} else {
currentValue = currentValue.filter(item => item !== e.target.value)
}
this.$emit('input', currentValue);
},
},
template: `<div>
<input
:id="index"
type="checkbox"
:value="inputValue"
#change="onChange" />
<label :for="index">
{{ label }}
</label>
</div>`,
})
new Vue({
el: "#app",
data: {
checkOptions: [
{
label: 'Option 1',
value: 'value of option 1',
},
{
label: 'Option 2',
value: 'value of option 2',
},
{
label: 'Option 3',
value: 'value of option 3',
},
{
label: 'Option 4',
value: 'value of option 4',
},
],
myCheckBoxModel: []
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
checked Checkboxes:
<span v-for="item in myCheckBoxModel"> {{ item }}; </span>
<ui-checkbox
v-for="(option, index) in checkOptions"
v-model="myCheckBoxModel"
:key="index"
:index="index"
:input-value="option.value"
:label="option.label" />
</div>
I don't know if you need to set checkbox state programmatically, i.e. when you change myCheckBoxModel the state of checkboxes changes correspondently. If you do, you need to watch value property in your ui-checkbox component: set the state of the check box in dependance of if its value is in value array. Do the same also in created hook if you want to initialize the state of checkboxes by myChexkboxModel
The solution presented by #Lana is just too complicated. The onChange method is not needed at all - what you want is to use build-in power of v-model. See below...
Vue.component('ui-checkbox', {
props: {
label: {
type: String,
required: true,
},
index: {
type: Number
},
inputValue: {
type: String
},
value: {
type: Array
}
},
computed: {
model: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
}
},
},
template: `<div>
<input
:id="index"
type="checkbox"
:value="inputValue"
v-model="model" />
<label :for="index">
{{ label }}
</label>
</div>`,
})
new Vue({
el: "#app",
data: {
checkOptions: [{
label: 'Option 1',
value: 'value of option 1',
},
{
label: 'Option 2',
value: 'value of option 2',
},
{
label: 'Option 3',
value: 'value of option 3',
},
{
label: 'Option 4',
value: 'value of option 4',
},
],
myCheckBoxModel: []
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
model: {{ myCheckBoxModel }}
<ui-checkbox v-for="(option, index) in checkOptions" v-model="myCheckBoxModel" :key="index" :index="index" :input-value="option.value" :label="option.label" />
</div>
NOTE that using v-for index as a key works in this case BUT is not recommended in general, especially if set of checkboxes is dynamic and can change over the lifetime of the component that is rendering them.

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.

How to delete a dynamically generated form based on the click of the delete button with respect to its ID in vuejs2

I am creating an application using Quasar and VueJS. I am able to generate a dynamic form on click of the add button, but not able to delete any of the newly generated form based on the click of the delete button.Find the code below:
<template>
<div v-for="h in htmlList">
<div v-for="r in h" >
<div v-html="r" v-on:click="useRemoveFromProject(1)" v-bind:id="r.id">
</div>
</div>
</div>
</template>
<script>
/*
* Root component
*/
import Vue from 'vue'
export default {
name: 'q-app',
data () {
return {
flag: 0,
htmlList: [],
select: 'fb',
select1: 'fb1',
multipleSelect: ['goog', 'twtr'],
usersInProject: [],
selectOptions: [
{
label: 'Google',
value: 'goog'
},
{
label: 'Select',
value: 'fb'
},
{
label: 'Twitter',
value: 'twtr'
},
{
label: 'Apple Inc.',
value: 'appl'
},
{
label: 'Oracle',
value: 'ora'
}
],
selectOptions1: [
{
label: 'Integer',
value: 'goog1'
},
{
label: 'Float',
value: 'fb1'
},
{
label: 'String',
value: 'twtr1'
}
]
}
},
methods: {
useRemoveFromProject: function (id) {
console.log('hi....')
Vue.delete(this.htmlList, id)
},
identifyMe: function (event) {
alert('hi - ' + event.target.id)
},
process: function () {
this.flag += 1
let temp = []
temp.push('<div class="card" id="a_' + this.flag + '"> <div class="card-content content-center "> <large id="l4">Expression LHS:</large> <input><br> <large id="l5">Operators:</large> <q-select type="radio" v-model="this.select" :options="this.selectOptions"></q-select><br><large id="l4">Expression RHS:</large> <input><br><large id="l5">Data type:</large> <q-select type="radio" v-model="select1" :options="selectOptions1"></q-select><br></div><button class="cordova-hide circular red " style="margin-bottom:5px; margin-right:30px;" v-on:click="userRemoveFromProject(i)"><i>delete</i></button><input value="click" type="button"> </div>')
let ids = ['a_' + this.flag]
console.log(ids)
this.htmlList.push(temp)
}
}
}
</script>
After looking to your code i noticed that you have some errors:
Call function useRemoveFromProject without the 'r' of 'user'
Call userRemoveFromProject when clicking on the element and not only the delete button
Call userRemoveFromProject(i) with a 'i' variable, but what is 'i' ?
Why using a double v-for? The first level is enough.
I propose to you a working example on a fiddle. Please let me know if it's useful for you (and mark it as resolve if it's the case).
EDIT: for Vue.js 2 https://jsfiddle.net/86216oko/