<select>
Like this article? Please leave feedback on development.thatoneplace.net!
I have a webpage that has two dropdowns. The second dropdown's options are dependent on the first's selected value(s).
I am using Vue to bind the options and selected values for both <select>
elements.
I am also using bootstrap-select to provide the user more elegant controls to make their selections.
bootstrap-select wraps and hides the original <select>
to use its own set of HTML elements for the nicer experience,
and keeps the original <select>
's selected value in sync in the JavaScript DOM. This allows the form to still be submitted without any extra work on your part
... normally ...
But using Vue for binding both the <option>
s and the selected value for your <select>
and you change the options on the Vue model,
Vue will properly update the now-hidden <select>
, but the bootstrap-select will not be updated.
As I mentioned before, bootstrap-select syncs the selected value, but it apparently does not sync the options.
Consider the example below:
We have a Genre dropdown and a Video Game dropdown. Select different Genres to change the Video Game options. The changed options will appear as JSON under the dropdowns, but you will notice the Video Game dropdown options remain as the old values.
{{ gameOptions }}
Play with the Video Game dropdown after changing the Genre. Each time you change Genre, click the Video Game drop down to see that the options remain the same, despite the JSON updating below. When on a different Genre than the default 'Racing', you should notice weirdness including, but not limited to,
<select>
's option via selectedIndex, but I haven't verified this.<select>
bootstrap-select offers a way to refresh itself, to re-sync the options from the original select. You must call this method explicitly AFTER Vue has performed its update.
We simply add a watch
to our Vue model so we can explicitly refresh the video game bootstrap-select,
using Vue's $nextTick
function to ensure binding updates for gameOptions
are completed first.
watch: {
gameOptions: function(newValues, oldValues){
this.$nextTick(function(){ $('#video-game-selector').selectpicker('refresh'); });
}
}
We have a Genre dropdown and a Video Game dropdown. Select different Genres to change the Video Game options. The changed options will appear as JSON under the dropdowns, but you will notice the Video Game dropdown options remain as the old values.
{{ gameOptions }}
class
like "select-picker" instead of "selectpicker" for your <select>
s and manually set them up after your Vue binding occurs.
class="selectpicker"
, bootstrap-select automatically hooks up the selectpicker control code,
but there seems to be a race condition that causes vue not to bind.
$nextTick
inside your mounted function to ensure any child components are also mounted before the bootstrap-select hookup happens.
Example:
new Vue({
el: '#yourElement',
data: {
// data properties here
},
mounted: function(){
this.$nextTick(function(){ $('select-picker').selectpicker(); });
}
});
title
attribute on your original <select>
if you DO NOT set default option(s).
title
is set.
It will honor the selected value if title
is not set. I observe this even when hooking bootstrap-select up after Vue is mounted.selected
attribute on an option (not using Vue binding)
<select>
's options.
Example:
computed: {
gameOptions(){
return this.games
.filter(game => game.genre === this.selectedGenre)
.map(game => { return { text: game.title, value: game.id }; });
}
},
watch: {
gameOptions: function(newValues, oldValues){
this.$nextTick(function(){ $('#video-game-selector').selectpicker('refresh'); });
}
}