Avoid Select options to be duplicated in vuejs - vuejs2

I am getting duplicate options in a multi select dropdown (select2).
I have a parent and a child select dropdowns. Everytime I select child option its parent gets populated too.
Eg : With Category & Subcategory dropdowns if I select 2 subcat from same category, its category gets populated twice.
<select style="width: 100%" multiple v-model="item.host_groups" v-select2 class="form-control select2" v-bind:id="'tmp_hostgroup_'+index" >
<option v-for=" option in hosts.host_mapping" v-if="item.hosts.includes(option.host_name)" :value="option.host_group" :key="option.host_group">#{{ option.host_group }}</option>
</select>
I have binded the value but still, see duplicates.
As in the screenshot below everytime I select Item that belong to same group the Item Group gets selected multiple times ending up with duplicates (AA in pic)
I also have onchange of select2
directives: {
select2: {
inserted: function(el) {
$(el).select2({
width: 'resolve',
allowClear: true,
}).on('select2:select', function() {
const event = new Event('change', {bubbles : true, cancelable: true}) ;
el.dispatchEvent(event);
});
}
},

Related

VueJS Using #click on <option> elements and #change on <select> element

I have a simple function that manipulates a data between true and false. I use it to make my div hidden and visible like a toggle. I also have a with three element. I found out that I cannot use #click for <option> elements, I need to use #change for my <select>.
But in this way, whenever an is selected, the function is being triggered and my data toggles between true and false. Here is my <select> element;
<select #change="isDisabled">
<option>Please select a security type</option>
<option>No Security</option>
<option>Personal</option>
<option>Enterprise</option>
</select>
IsDisabled function takes a variable and change its values between true and false so my div becomes hidden and visible as follows;
<div v-if="noSecurity">something</div>
But here is the thing, I only want to trigger the function when the user select the "No Security" option. Now it's being triggered whenever I select an option, so it turned out to be some kind of a toggle. But I want to hide the div when I select the "No Security" option and show the div if something different is selected. What should I do?
I've made a CodeSandbox where you could see the result :
https://codesandbox.io/s/magical-meitner-63eno?file=/src/App.vue
But here is the explanation:
<template>
<section>
<select #change="isDisabled">
<option>Please select a security type</option>
<option>No Security</option>
<option>Personal</option>
<option>Enterprise</option>
</select>
<div v-if="noSecurity">You Choose no security, that's dangerous !</div>
</section>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
data() {
return {
noSecurity: false,
};
},
methods: {
isDisabled(e) {
console.log("e", e.target.value);
if (e.target.value === "No Security") {
// do your change
return (this.noSecurity = !this.noSecurity);
}
// to allow reset if another option is selected
if (this.noSecurity) {
return this.noSecurity = false;
}
},
},
};
</script>
Basically when you use the #change handler, your function will receive an event, in this event you can catch the target value with event.target.value.
Doing so, you do a condition if the value is equal to No Security (so the selected item), you change your state, if it's not No Security, you do nothing, or you do something else you would like to do.
Appart from that, I advice you to change your method name isDisabled to a global convention name like handleChange, or onChange.
Pass id values in your option so when you get the select event you're clear that No security or whatver the name you would like to change will be the same.
Because if one day you change No security to another name, you have to update all your conditions in your app. Try to avoid conditions with strings values like this if you can.
<option value="1">No Security</option> // :value="securityType.Id" for example if coming from your database
<option value="2">Personal</option>
<option value="3">Enterprise</option>
then in your function it will be
if (e.target.value === noSecurityId) {
// do your change
this.noSecurity = !this.noSecurity;
}
//...
There's no need for the additional noSecurity variable. Create your select with v-model to track the selected value. Give each option a value attribute.
<select v-model="selected">
<option value="">Please select a security type</option>
<option value="none">No Security</option>
<option value="personal">Personal</option>
<option value="enterprise">Enterprise</option>
</select>
Check that value:
<div v-if="selected === 'none'">something</div>
You can still use the noSecurity check if you prefer by creating a computed:
computed: {
noSecurity() {
return this.selected === 'none';
}
}
Here's a demo showing both:
new Vue({
el: "#app",
data() {
return {
selected: ''
}
},
computed: {
noSecurity() {
return this.selected === 'none';
}
},
methods: {},
created() {}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select v-model="selected">
<option value="">Please select a security type</option>
<option value="none">No Security</option>
<option value="personal">Personal</option>
<option value="enterprise">Enterprise</option>
</select>
<div v-if="selected === 'none'">something</div>
<div v-if="noSecurity">something</div>
</div>
Is using v-model instead of using a method is option for you? If it is, please try the following:
HTML:
<div id="hello-vue" class="demo">
<select v-model="security">
<option>Please select a security type</option>
<option>No Security</option>
<option>Personal</option>
<option>Enterprise</option>
</select>
<div v-if="security=='No Security'">something</div>
</div>
JS:
const HelloVueApp = {
data() {
return {
security: undefined
}
}
}

Pre-select a VUE2 drop-down

I have a vue2 app which I need to pre-select a dropdown but for the life of me, I can't figure it out.
I have looked and tried everything in:
How to preselect current value in a select created with v-repeat in Vue.js
Normal HTML
<select ref="courierList" id="courierList" class="form-control" v-model="shippingDetails.selectedCourier" #change="selectedCourierDd">
<option :value="courier.name" v-for="(courier, i) in couriers" :key="i">
{{ courier.name }}
</option>
</select>
data() {
return {
couriers: [],
.... OTHER DATA ITEMS
}
},
beforeMount() {
this.fetchCouriers();
},
fetchCouriers() {
axios.get('/couriers')
.then((response) => {
this.couriers = response.data.couriers;
.... OTHER CODE
Tried code > 1
Adding the below to the option
selected="{{ courier.name === preselectedCourierName ? 'true' : 'false' }}">
also tied without the true/false
Tried code > 2
Adding the below to the option
v-bind:selected="courier === preselectedCourierName"
and the below
data() {
return {
.... OTHER DATA ITEMS
preselectedCourier: [],
preselectedCourierName: ''
}
fetchCouriers() {
axios.get('/couriers')
.then((response) => {
this.couriers = response.data.couriers;
.... OTHER CODE
console.log('couriers', this.couriers[0])
this.preselectedCourier = this.couriers[0];
this.preselectedCourierName = this.preselectedCourier.name;
console.log('preselectedCourier', this.preselectedCourier)
console.log('preselectedCourierName', this.preselectedCourierName)
gives
Tried code > 3
<option :value="courier.name" v-for="(courier, i) in couriers" :key="i" :selected="courier.name === 'APC'">
no errors but dropdown still not pre-selected
The fix is in the mounted hook set the v-model of the select
<select v-model="shippingDetails.selectedCourier">
mounted() {
this.shippingDetails.selectedCourier = 'APC';
}
Give me exactly what i wanted

VueJs drop-down first item not selected on initial load

I have a drop-down option working with an array of items. I want to add the first selection/option as Select a Site.
When the element is rendered, the drop-down does not show the Select a Site initially. The drop-down element does have the array in the drop-down options.
The first image shows the initial state of the drop-down (looks
empty, but its not)
The second image is when the drop-down element is
when selected.
How can I the drop-down working with the Select a Site shown as the first option?
<select id="ddSite" name="ddSite" class="form-control m-b-10" v-on:change="onChangeSite($event)" v-model="ddSite">
<option :value="null">-- Select a Site --</option>
<option v-for="option in sites" v-bind:value="option.SiteId">
{{ option.SiteName }}
</option>
</select>
new Vue({
el: '#app',
data: {
sites: [],
ddSite:""
},
mounted() {
axios.get("/api/sites/" + this.companyid)
.then(response => {
this.sites = response.data
});
},
methods: {
onChangeSite: function (e) {
var self = this;
var siteid = e.target.value;
var sitename = e.target.options[e.target.options.selectedIndex].text;
},
In your code, you're binding the select's value to ddSite.
The -- Select a Site -- option has a value of null, but your ddSite data starts off as an empty string.
In order to have that option selected initially, you must init ddSite as null:
new Vue({
el: '#app',
data: {
ddSite: null,
sites: [{
SiteId: 1,
SiteName: 'Google',
},
{
SiteId: 2,
SiteName: 'Facebook',
},
{
SiteId: 3,
SiteName: 'StackOverflow',
},
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select id="ddSite" name="ddSite" v-model="ddSite">
<option :value="null">-- Select a Site --</option>
<option v-for="option in sites" :value="option.SiteId">
{{ option.SiteName }}
</option>
</select>
</div>

Computed properties in vue not reflected in select list

I have a vue component that is meant to create a select list with all available options. The save method puts the saved value into a vuex store. The available fields are generated using a computed property on the component that calls the vuex getter for the list.
In the component, there's a v-for with a v-if that checks that the select item isn't already being used by another component (by looking at a mapped property on the list item object).
Testing this, everything seems to be working as expected, the vuex store gets the list, it accepts the update, and once a save is called, the destination field is marked as mapped and that mapped property is visible in the vuex debug panel.
However, the other select lists on the page don't get updated to reflect the (now shorter) list of available options.
Once the select item is selected in another instance of the component, I'd expect the other components to drop that select option- but it appears the v-if is not re-evaluated after the initial load of the component?
Sorry, here's the basic component:
<template>
<div class="row">
<div class="col-4">
{{ item.source_id }}
</div>
<div class="col-8">
<select v-model="destination" class="form-control form-control-sm">
<option v-for="dest in destinationFields" v-if="shouldShow(dest)" v-bind:value="dest.id">{{ dest.id }} - {{ dest.label }} ({{ dest.dataType }})</option>
</select>
</div>
</div>
</template>
<script>
export default {
props: ['item'],
data() {
return {
destination: ''
}
},
methods: {
shouldShow: function(dest) {
if (this.hideDestination && (!dest.hasOwnProperty('mapped') || dest.id === this.destination)) {
return true
} else if (!this.hideDestination) {
return true
}
return false
}
},
computed: {
destinationFields: function() {
return this.$store.getters.visibleDestination
},
hideDestination: function() {
return this.$store.getters.hideMappedDestinations // boolean
}
}
}
I think a better approach would be to already filter the data inside of your computed function as follows:
computed: {
destinationFields: function() {
return this.$store.getters.visibleDestination()
.filter(dest => !dest.hasOwnProperty('mapped') || dest.id === this.destination)
},
hideDestination: function() {
return this.$store.getters.hideMappedDestinations // boolean
}
}
You would also have to change your template to:
<select v-model="destination" class="form-control form-control-sm">
<option v-for="dest in destinationFields" v-bind:value="dest.id">{{ dest.id }} - {{ dest.label }} ({{ dest.dataType }})</option>
</select>

Get text from select element using vue 2, when options has value attribute

I have a select element within a vue component that looks like this:
<template>
<select v-model="item.value" >
<option value="1">A</option>
<option value="2">B</option>
</select>
<div>
You selected {{item.text}} with a value of {{item.value}}
<div>
</template>
<script>
export default {
data() {
return {
item: {
text: '',
value: 0
}
}
}
}
</script>
If I make a selection, on A, I get a value of 1, if I make a selection on B. I get a value of 2. So item.value will be populated. How do I fill up item.text?
If I remove the value attribute from the options, I get the answer, but now my value wouldn't be populated.
I'd recommend using an array of objects that hold both the value and text for each <option>. For example
data() {
return {
// ...
options: [
{ value: 1, text: 'A' },
{ value: 2, text: 'B' }
]
}
}
Then you can use a v-for to iterate this list and simply bind the selected item with v-model
<select v-model="item">
<option v-for="opt in options" :key="opt.value" :value="opt">
{{opt.text}}
</option>
</select>
See https://v2.vuejs.org/v2/guide/forms.html#Select-Options