Vuejs dynamically disable dropdown option - vuejs2

I have two select boxes, for the second the values can be disabled depending on the first
<div id="app">
<h2>Todos:</h2>
<select v-model="hoursDayB" #change='disableOptions()'>
<option v-for='dataB in hours' :value='dataB.id'>{{ dataB.name }}</option>
</select>
<select v-model="hoursDayE">
<option v-for='dataE in hours' :disabled="dataE.id < hoursDayB" :value='dataE.id'>{{ dataE.name }}</option>
</select>
</div>
new Vue({
el: "#app",
data: {
hours:[],
hoursDayB: 0,
hoursDayE: 0,
},
methods: {
getHoursDays: function(){
this.hours = JSON.parse('[{"id":"0","name":"00:00","disabled":1},{"id":"1","name":"01:00","disabled":1},{"id":"2","name":"02:00","disabled":1},{"id":"3","name":"03:00","disabled":1},{"id":"4","name":"04:00","disabled":1},{"id":"5","name":"05:00","disabled":1},{"id":"6","name":"06:00","disabled":1},{"id":"7","name":"07:00","disabled":1},{"id":"8","name":"08:00","disabled":1},{"id":"9","name":"09:00","disabled":1},{"id":"10","name":"10:00","disabled":0},{"id":"11","name":"11:00","disabled":0},{"id":"12","name":"12:00","disabled":0},{"id":"13","name":"13:00","disabled":0},{"id":"14","name":"14:00","disabled":0},{"id":"15","name":"15:00","disabled":0},{"id":"16","name":"16:00","disabled":0},{"id":"17","name":"17:00","disabled":0},{"id":"18","name":"18:00","disabled":0},{"id":"19","name":"19:00","disabled":0},{"id":"20","name":"20:00","disabled":0},{"id":"21","name":"21:00","disabled":0},{"id":"22","name":"22:00","disabled":0},{"id":"23","name":"23:00","disabled":0}]');
},
disableOptions: function(){
},
},
created: function(){
this.getHoursDays();
}
})
The problem that the values is disabled randomly
https://jsfiddle.net/hams123/1w6u8q4h/1/

The comparison was in string, so we must cast to integer
<div id="app">
<select v-model="hoursDayB" #change='disableOptions()'>
<option v-for='dataB in hours' :value='dataB.id'>{{ dataB.name }}</option>
</select>
<select v-model="hoursDayE">
<option v-for='dataE in hours' :disabled="(parseInt(dataE.id)) < (parseInt(hoursDayB))" :value='dataE.id'>{{ dataE.name }}</option>
</select>
</div>
https://jsfiddle.net/hams123/1w6u8q4h/7/

Related

Vue.js methods not working when input changed

I write two inputs by same change function in Vue but when inputs changed, birthday_changed method works just on one input. What should I do to resolve this problem ?
<select v-model="client.day" id="birthday_day">
<option v-for="day in 31" :key=day :value="('0' + day).slice(-2)">{{ ("0" + day).slice(-2) }}</option>
</select>
<select v-model="client.year" #change="birthday_changed" id="birthday_year">
<option v-for="year in 81" :key=year :value="1320 + year"> {{ 1320 + year }} </option>
</select>
birthday_changed: function () {
alert('changed');
},
Just add your onchange #change event to the first select.
<select v-model="client.day" id="birthday_day" #change="birthday_changed" >
<option v-for="day in 31" :key=day :value="('0' + day).slice(-2)">{{ ("0" + day).slice(-2) }}</option>
</select>
const { createApp } = Vue;
const App = {
data() {
return {
client: { day: 1, year: 1}
}
},
methods: {
birthday_changed: function () {
alert('changed: ' + JSON.stringify(this.client));
},
}
};
createApp(App).mount("#app");
<div id="app">
<select v-model="client.day" #change="birthday_changed" id="birthday_day">
<option v-for="day in 31" :key=day :value="('0' + day).slice(-2)">
{{ ("0" + day).slice(-2) }}
</option>
</select>
<select v-model="client.year" #change="birthday_changed" id="birthday_year">
<option v-for="year in 81" :key=year :value="1320 + year"> {{ 1320 + year }} </option>
</select>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>

Vue.js v-bind:value to empty object

I have a dropdown that is populated with an array of objects.
<select v-model="selectedLeague" v-on:change="chooseLeague()">
<option v-for="league in model.leagues" v-bind:value="league">
{{ league.name }}
</option>
</select>
At initialization, selectedLeague is {}
I want to add a default option that is selected when the object is empty. I tried adding
<option disabled v-bind:value=null>Choose League</option>
But that will not work because it is never null. What can I add to check if the object is empty using data binding? I am using version 2.4.4 btw
Since selectedLeague is initially {}, you can use:
<option disabled v-bind:value="{}">Choose League</option>
Demo:
new Vue({
el: '#app',
data: {
selectedLeague: {},
model: {
leagues: [{name: 'leagueOne'},{name: 'leagueTwo'}]
}
},
methods: {
chooseLeague() { console.log('chooseLeague()', this.selectedLeague); }
}
})
<script src="https://unpkg.com/vue#2.4.4"></script>
<div id="app">
<select v-model="selectedLeague" v-on:change="chooseLeague()">
<option disabled v-bind:value="{}">Choose League</option>
<option v-for="league in model.leagues" v-bind:value="league">
{{ league.name }}
</option>
</select>
</div>
Note: you can also add hidden if you want to hide that option from the dropdown:
<option disabled v-bind:value="{}" hidden>Choose League</option>

How can I add class="required" in the following select v-model?

<div v-for="value in day" class="checkboxFour">
<input type="checkbox" id="need" value="value.val" v-model="value.selected" style="width: 10%!important;">
<label for="need" style=" width: 30%!important;">{{value.name}}</label>
<select v-model="value.from" class="select-style">From
<option value="08:00">08.00</option>
<option value="12:00">12.00</option>
<option value="20:00">20.00</option>
<option value="23:00">23.00</option>
</select>
<select v-model="value.to" class="select-style">To
<option value="08:00">08.00</option>
<option value="12:00">12.00</option>
<option value="20:00">20.00</option>
<option value="23:00">23.00</option>
</select>
<br>
</div>
This is select option. When I use required="". I am getting getAttribute error. How can I able to correct the same?
Also how can I use selected in the following case? My target is select a particular value previously and then user can change according to his need? Please help me to obtain the same?
The required attribute is a boolean (an not a class). You don't need to give it a value; if it is present in the select tag, the select is required.
You can also bind it to a boolean value to change whether the select is required.
new Vue({
el: '#app',
data: {
isRequired: false
}
});
[required] {
outline: thin solid red;
}
<script src="//unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<select required>
<option>An option</option>
</select> This one is always required
<div>
<select :required="isRequired">
<option>Whatever</option>
</select>
<input type="checkbox" v-model="isRequired"> Is Required: {{isRequired}}
</div>
</div>
As it mentioned in Vue.JS docs you can use v-bind:class to achieve what you wanted:
<select v-model="value.from" v-bind:class="{required: isRequired}">
which required is data, computed field in your app/component.
Update 1:
new Vue({
el: "#myApp",
data: {
// you should define a variable in your data
isRequired: false
},
methods: {
doSomething: function(){
this.isRequired = true;
}
}
});

Set same value for sibling component's select

Using v-for, I am looping through a component. The component is for each client. In this component, I have same form for each client and when a select value is selected for the first component (client 1), I want to select this value for every client.
Do I need to pass the data to the root and create a single source of truth variable?
I tried setting up a basic version:
<div id="app">
<my-comp v-for="x in 2" v-bind:val="x"></my-comp>
</div>
Vue.component('my-comp', {
props: ['val'],
template: `
<div>
<div>
<label>Status</label>
<select :data-client="val" #change="statusChanged">
<option selected="" disabled="" value="0"></option>
<option value="xxx">Xxx</option>
<option value="yyy">Yyy</option>
<option value="zzz">Zzz</option>
</select>
</div>
</div>
`,
methods: {
statusChanged(e) {
var client = e.target.getAttribute('data-client')
if (client == 1) {
alert('set same value for client 2')
}
}
}
})
new Vue({
el: '#app',
})
Here is a fiddle: https://jsfiddle.net/w53164t2/
I considered a little bit after my original answer and have come up with something I think is a little bit more real world than the example fiddle provided in the original question; specifically it is easy to make all the selects reflect the same value if they are all using the same source value, however I expect in a real world scenario each component would be independently bound to a single client. Each client would want their individual value to change, with the one caveat that if a "master" client changed, then all non-master clients should change to the master client's value.
To that end, this might be a case where I think a component specific bus is appropriate. The master would emit an event when it's value changed and the the other clients would set their value with respect to the master.
console.clear()
const MyCompBus = new Vue()
Vue.component('my-comp', {
props: ['val', 'master'],
computed:{
selected:{
get(){return this.val},
set(v){
this.$emit('update:val', v)
if (this.master)
MyCompBus.$emit("master-updated", v)
}
}
},
methods:{
onMasterUpdated(newMasterValue){
if (this.master) return
this.selected = newMasterValue
}
},
created(){
MyCompBus.$on('master-updated', this.onMasterUpdated)
},
beforeDestroy(){
MyCompBus.$off('master-updated', this.onMasterUpdated)
},
template: `
<div>
<div>
<label>Status</label>
<select v-model="selected">
<option selected="" disabled="" value="0"></option>
<option value="xxx">Xxx</option>
<option value="yyy">Yyy</option>
<option value="zzz">Zzz</option>
</select>
</div>
</div>
`,
})
new Vue({
el: '#app',
data:{
masterValue: null,
clients:[
{id: 1, selectedValue: null, master: true},
{id: 2, selectedValue: null},
{id: 3, selectedValue: null},
{id: 4, selectedValue: null},
]
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<my-comp v-for="client in clients"
:val.sync="client.selectedValue"
:master="client.master"
:key="client.id">
</my-comp>
{{clients}}
</div>
Original Answer
Bind them all to the same value using v-model.
Vue.component('my-comp', {
props: ['value'],
computed:{
selected:{
get(){return this.value},
set(v){this.$emit('input', v)}
}
},
template: `
<div>
<div>
<label>Status</label>
<select v-model="selected">
<option selected="" disabled="" value="0"></option>
<option value="xxx">Xxx</option>
<option value="yyy">Yyy</option>
<option value="zzz">Zzz</option>
</select>
</div>
</div>
`,
})
And in the template:
<my-comp v-for="x in 2" v-model="selectedValue" :key="x"></my-comp>
Here is the updated fiddle.
If you want to stick with val as the property you can use .sync instead.
Vue.component('my-comp', {
props: ['val'],
computed:{
selected:{
get(){return this.val},
set(v){this.$emit('update:val', v)}
}
},
template: `
<div>
<div>
<label>Status</label>
<select v-model="selected">
<option selected="" disabled="" value="0"></option>
<option value="xxx">Xxx</option>
<option value="yyy">Yyy</option>
<option value="zzz">Zzz</option>
</select>
</div>
</div>
`,
})
And in the template:
<my-comp v-for="x in 2" :val.sync="selectedValue" :key="x"></my-comp>
Example fiddle.
If you want just one of them designated as a "master" select, then add a property that does so.
Vue.component('my-comp', {
props: ['val', 'master'],
computed:{
selected:{
get(){return this.val},
set(v){if (this.master) this.$emit('update:val', v)}
}
},
template: `
<div>
<div>
<label>Status</label>
<select v-model="selected">
<option selected="" disabled="" value="0"></option>
<option value="xxx">Xxx</option>
<option value="yyy">Yyy</option>
<option value="zzz">Zzz</option>
</select>
</div>
</div>
`,
})
And in the template:
<my-comp v-for="x in 5" :val.sync="selectedValue" :master="1 == x" :key="x"></my-comp>
Example fiddle.

How to return boolean and not string when using select?

I have this:-
<div class="form-group">
<label for="">Allow Multiple</label>
<select class="form-control" v-model="allowMultiple">
<option value=true>Yes</option>
<option value=false>No</option>
</select>
</div>
I set allowMultiple=true when I initialize it, but when I select No then allowMultiple='false' So its no longer a Boolean but a String? How to get it to be Boolean?
In HTML, if you set attribute value in a tag, the value will be default type--string.So you can use vue v-model to bind it to other type value, for example, Boolean, Number and etc.
Following code is working, the result is what you want
new Vue({
el:'#app',
data: {
allowMultiple: false
},
methods: {
print: function () {
alert(this.allowMultiple);
}
}
})
<div class="form-group" id='app'>
<label for="">Allow Multiple</label>
<select class="form-control" v-model="allowMultiple" #change='print'>
<option :value='true'>Yes</option>
<option :value='false'>No</option>
</select>
</div>
<script src="https://unpkg.com/vue#2.4.2/dist/vue.min.js"></script>
Here is a way to do it in Vue.
Instead of hard coding your options in html. Use the Vue way, set an array of options in your Vue data then use v-for to render all the options from the array.
Each option should have 2 properties: a text and a value. The value should be the boolean you are looking for.
Now whenever the user changes the selected option, it will always be boolean.
new Vue({
el: '#app',
data: {
allowMultiple: true,
options: [
{text: 'Yes', value: true},
{text: 'No', value: false},
],
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<div id="app">
<div class="form-group">
<div>Allow multiple: {{allowMultiple}} [Type: {{typeof allowMultiple}}]</div><br>
<label for="">Allow Multiple</label>
<select class="form-control" v-model="allowMultiple">
<option v-for="option in options" :value="option.value">{{option.text}}</option>
</select>
</div>
</div>
The easier and quicker way I found that works for me is this:
<select id="selected" v-model="item.selected">
<option :value=0>No</option>
<option :value=1>Yes</option>
</select>
Maybe it's useful for anyone.
Try this:
<option value=1>Yes</option>
<option value=0>No</option>