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.
Related
I'm new to vue, I still don't understand everything, tell me. I have buttons that I display through v-for, I need to get the active class of only one button when pressed, all the others need to be turned off, tell me, preferably visually, how can I do it better?
I am using the method activeBtn, but this doesn't turn off the active class from the previous buttons
activeBtn(event, index) {
this.buttons[index].isActive = !this.buttons[index].isActive;
<script>
data() {
return {
buttons: [
{
label: "A",
isActive: false,
type: "border-left",
name: "BorderLeftComonent",
},
{
label: "A",
isActive: false,
type: "text-balloon",
name: "TextBalloonComponent"
},
{
label: "A",
isActive: false,
type: "dashed",
name: "DashedComponent"
},
],
};
},
methods: {
activeBtn(event, index) {
this.buttons[index].isActive = !this.buttons[index].isActive;
}
</script>
<template>
<div id="btn-box">
<button
v-for="(button, index) in buttons"
:key="index"
:class="button.isActive ? 'on' : 'off'"
#click="component = button.name, activeBtn($event, index)">
<div :class="`btn btn-${button.type}`">{{ button.label }}</div>
</button>
</div>
</template>
Since you only want to get one active button at any one point, it doesn't make sense to manage the active state inside each button.
Instead, you should manage it at group level by storing the currently selected button's id. A button would then be active when its id matches the currently selected id.
Here's an example:
new Vue({
el: '#app',
data: () => ({
buttons: [
{
id: "button-1",
label: "A",
type: "border-left",
name: "BorderLeftComonent"
},
{
id: "button-2",
label: "A",
type: "text-balloon",
name: "TextBalloonComponent"
},
{
id: "button-3",
label: "A",
type: "dashed",
name: "DashedComponent"
}
],
activeButtonId: "button-1"
}),
methods: {
activate(id) {
this.activeButtonId = id;
}
}
})
.on {
background-color: red
}
.off {
background-color: blue
}
.on, .off {
color: white
}
<script src="https://unpkg.com/vue#2/dist/vue.min.js"></script>
<div id="app">
<div>
<button
v-for="{id, type, label} in buttons"
:key="id"
:class="activeButtonId === id ? 'on' : 'off'"
#click="activate(id)"
>
<div :class="`btn btn-${type}`" v-text="label" />
</button>
</div>
</div>
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>
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
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.
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/